Compare commits

...
197 Commits
Author SHA1 Message Date
jack 48db5502d7 Notes icon: turn blue immediately when sheet shows notes by passing count up from sheet (closure) and OR-ing with counter; reset on sheet close 2025-09-13 14:18:38 +02:00
jack 0a9a59a7a6 Notes subscribe: fallback to default relays when GeoRelayDirectory has no entries (pass nil relayUrls) so counter/icon turn blue and sheet loads even before georelay fetch 2025-09-13 13:29:41 +02:00
jack 887faa89ac Notes icon: force a one-shot location refresh before (re)subscribing the counter so icon turns blue immediately on current 8-cell 2025-09-13 13:16:29 +02:00
jack 58eb83b73a Notes sheet: add light haptic feedback when building geohash changes (iOS only) 2025-09-13 12:56:41 +02:00
jack 24cebfebf2 Notes header: bold count text; ensure sheet updates when building geohash changes by calling manager.setGeohash on geohash change 2025-09-13 12:47:23 +02:00
jack 0a151f51df Notes header: move count before title as '<N> note(s) @ #gh'; remove parentheses; keep count non-bold 2025-09-13 12:39:02 +02:00
jack 8c9bfaa20e Notes header: show count as '(N note/notes)' with non-bold, secondary styling next to title 2025-09-13 12:33:49 +02:00
jack e08e5c8e65 Notes header: show count in parentheses; icon shows blue if any notes, grey if none; only start live location updates while sheet is open; reduce nickname width; set live distance filter to 10m 2025-09-13 12:31:02 +02:00
jack 78f1bd3ad9 Notes counter: subscribe only to building geohash (precision 8) so count reflects current 8-cell; auto-begin live location refresh on mesh (and permission) to update as you walk 2025-09-13 12:19:44 +02:00
jack 6cf6e3c420 Notes: subscribe counter to building + parent block (merge results); hide notes icon unless location is authorized; replace 10s timer with live location updates while sheet open 2025-09-13 12:09:41 +02:00
jack 8cc6d538ae Notes header: show building name when available (fallback to block name) 2025-09-13 12:04:14 +02:00
jack f10e5d1788 Notes counter: show 0 by default; subscribe at building-level (precision 8) for notes and counter; keep building hidden in channel list 2025-09-13 11:59:55 +02:00
jack 5bf28e5ba4 Fix Swift 6 isolation: hop to @MainActor inside Timer callback for EOSE tracker mutations 2025-09-13 11:53:19 +02:00
jack fecebb05d5 Nostr: add EOSE handling with callback support for subscriptions; wire to LocationNotesManager/Counter (initialLoadComplete). Remove 'building' level from channel enum and geocoder mapping; geohash list shows block/neighborhood/city/province/region only 2025-09-13 11:44:37 +02:00
jack b7e76e6da4 Location notes: show block name (from reverse geocode) in header instead of 'street-level notes' 2025-09-13 11:35:23 +02:00
jack eb63a62590 Revert notes geohash selection back to block-level (precision 7); keep building level available but unused; update counter and sheet accordingly 2025-09-13 11:29:49 +02:00
jack 939adcf1cb Location notes: change notes toolbar icon to SF Symbol 'long.text.page.and.pencil' 2025-09-13 11:27:46 +02:00
jack 46ca37ceaa Switch location notes and UI helpers to building-level geohash (precision 8): add GeohashChannelLevel.building, map length 8, use building for notes selection and counter, add building name mapping 2025-09-13 11:08:38 +02:00
jack ead1d1e9a2 Location notes: append 'ago' to relative timestamps (within 7 days) 2025-09-13 10:37:05 +02:00
jack e0f69d7f59 Location notes: show timestamp as relative within 7 days, else absolute date (MMM d or MMM d, y); keep monospaced styling 2025-09-13 10:36:26 +02:00
jack cd3dea3dc4 Location notes: drop 'teleport' tag from kind-1 events; simplify note builder API and usage 2025-09-13 10:32:35 +02:00
jack 086699961d Location notes: restore timestamps in notes list; remove loading state from manager and sheet (no spinner/animation) 2025-09-13 10:31:17 +02:00
jack d0bfb179ed Location notes: move notes icon to the right of #mesh badge in toolbar 2025-09-13 01:15:15 +02:00
jack 52bdf6745b Location notes: add background counter service and show count next to notes icon on mesh; auto-subscribe to current block geohash 2025-09-13 01:12:49 +02:00
jack bef4a30ea7 Location notes: fix intermittent first load by ensuring resubscribe after geohash change, removing over-eager subscribe guard, and widening note fetch window (no since filter) 2025-09-13 01:09:35 +02:00
jack c97de7a2f8 Location notes: remove per-note relative timestamp from sheet (no seconds display) 2025-09-13 01:07:32 +02:00
jack 9fd5957f46 Location notes: remove Matrix animation; use simple spinner when acquiring location; simplify notes view layout 2025-09-13 01:04:58 +02:00
jack 7eba856f13 Location notes: inline sheet wrapper to avoid missing file in target; force location refresh and show Matrix loader until block geohash resolves 2025-09-13 01:02:20 +02:00
jack 3a3da2f66d Location notes: acquire geohash on open (force refresh) and show Matrix loader until block-level geohash resolves; add LocationNotesSheet wrapper 2025-09-13 01:00:55 +02:00
jack 52933568d7 Location notes: add close (x) button in sheet header (upper-right) using @Environment(\.dismiss) 2025-09-13 00:55:47 +02:00
jack abeab5ae94 Location notes: render note bodies with monospaced font in notes list 2025-09-13 00:52:01 +02:00
jack 4a2d83ec78 Location notes: fix duplicate state redeclaration in ContentView 2025-09-13 00:48:12 +02:00
jack 56590c8ac3 Location notes: prevent duplicate loading/subscriptions (StateObject manager, geohash captured at open, guard subscribe) 2025-09-13 00:46:50 +02:00
jack d809351ab3 Location notes: Matrix loader with 1–3s minimum display; allow multiple notes; wire notes UI from mesh toolbar 2025-09-13 00:40:41 +02:00
920dc31795 Refactor: Testable Keychain and Identity Manager (#584)
* Make static functions instance functions to be testable

* Injectable KeychainManager + Mock + updated tests

* Remove `pendingActions` from identity manager (dead code)

* Remove `getHandshakeState` from identity manager (dead code)

* Remove `getAllSocialIdentities` from identity manager (dead code)

* Remove `getCryptographicIdentity` from identity manager (dead code)

* Remove `resolveIdentity` from identity manager (dead code)

* Identity Manager: minor clean up

* Put Identity Manager behind a protocol

* Remove Keychain and Identity Manager singletons

* Tests: include MockKeychain/MockIdentityManager in project; init identityManager in CommandProcessorTests

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-09-12 14:37:34 +02:00
bb3d99bdca Fix repeated favorite notifications; route system messages to mesh; simplify favorites (#588)
* Favorites: mesh-only system message; stop reconnect resends; gate system on state change

* Favorites: remove npub resend tracking and nickname-based key migration; rely on Noise key as identity

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-09-12 14:36:32 +02:00
jackandGitHub b01cac4649 Delete Frameworks/README.md 2025-09-12 13:16:08 +02:00
4b0634d1d0 Fix/general queue (#580)
* Fix emote targeting and grammar; add tests

Prevent 'system' mis-target via peerID-derived display name in actions sheet. Correct /hug and /slap usage/error grammar by passing base command name. Improve geohash nickname resolution to match displayName with #suffix. Add CommandProcessor tests.

* Geohash ordering: strict in-order inserts and timestamp clamp

Use channel-aware late-insert threshold with 0s for geohash to keep strict chronological order. Clamp future Nostr event timestamps to 'now' to avoid future-dated items skewing order in geohash timelines.

* Trim trailing/leading spaces in geohash nicknames and tag emission

Sanitize Nostr 'n' tag values on ingest and emit by trimming whitespace/newlines to prevent trailing spaces in displayed usernames. Local nickname is already trimmed on focus loss and submit.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-09-11 21:02:48 +02:00
jack 97cbe37f09 Project: add OSLog+Categories.swift to iOS/macOS targets to fix missing OSLog categories (noise/security/keychain/etc.) 2025-09-11 20:14:00 +02:00
jack b5d6e4eeb5 Merge branch 'pr/575' 2025-09-11 20:07:04 +02:00
islam a1edf29bd3 Remove unnecessary import os.logs 2025-09-11 19:03:08 +01:00
islam 5f402698a1 Extract private functions into a separate extension 2025-09-11 19:03:08 +01:00
islam 1e997e1387 Statically typed logging of KeyOperations 2025-09-11 19:03:08 +01:00
islam e602024617 Remove dead code 2025-09-11 19:03:08 +01:00
islam deb464f5d8 Remove redundant .noise 2025-09-11 19:03:08 +01:00
islam e5a415d885 Overloading .debug/.error for ‘.logSecurityEvent’
Search/Replace Strategies:

1.
Search regex: `SecureLogger\.logSecurityEvent\(\s*(.*?),\s*level:\s*\.(\w+)\s*\)`
Replace regex: `SecureLogger.$2($1)`

Sample input:
`SecureLogger.logSecurityEvent(.authenticationFailed(peerID: peerID), level: .warning)`

Sample output:
`SecureLogger.warning(.authenticationFailed(peerID: peerID))`

---

2.
Search regex: `SecureLogger\.logSecurityEvent\(\s*(.*?)\s*\)`
Replace regex: `SecureLogger.info($1)`  (`info` is the default level)

Sample input:
`SecureLogger.logSecurityEvent(.handshakeStarted(peerID: peerID))`

Sample output:
`SecureLogger.info(.handshakeStarted(peerID: peerID))`
2025-09-11 19:03:08 +01:00
islam b5382b129e Rename logError(…) to error(…) 2025-09-11 19:03:08 +01:00
islam 5d6aecfc83 Replace .log w/ explicit .debug/.error functions
This would make the intention more explicit so we can overload different logging types as well like keychain, security events, etc…

Search/Replace Strategies:

1.
Search regex: `SecureLogger\.log\(\s*(.*?),\s*category:\s*(.*?),\s*level:\s*\.(\w+)\s*\)`
Replace regex: `SecureLogger.$3($1, category: $2)`

Sample input:
```
SecureLogger.log(
    "🔄 Found favorite for '\(peerInfo.nickname)' by nickname, updating noise key",
    category: .session,
    level: .debug
)
```

Sample output:
`SecureLogger.debug("🔄 Found favorite for '\(peerInfo.nickname)' by nickname, updating noise key", category: .session)`

---

2.
Search regex: `SecureLogger\.log\((.*?)\)`
Replace regex: `SecureLogger.debug($1)` (as it’s the default level)

Sample input:
`SecureLogger.log("some text")`

Sample output:
`SecureLogger.debug("some text")`

---

3
Manual changes:
ChatViewModel line 5393 (commented code)
NostrRelayManager line 196 (commented code)
NostrRelayManager lines 346-350 (if/else logic)
NostrRelayManager line 371 (commented code)
2025-09-11 19:03:08 +01:00
islam 5ca9222fc2 Make logging categories static properties of OSLog
So we can use `.<category name>` to simplify the code.

Search/Replace Strategy:
Search text: `category: SecureLogger.`
Replace text: `category: .`
2025-09-11 19:02:32 +01:00
jack ee16ff5ff4 Fix Nostr subscriptions: connect on subscribe; handle inbound frames correctly\n\n- Call ensureConnections(to:) in subscribe() so queued REQs open sockets immediately and flush after ping\n- Correct ParsedInbound failable initializer to return parsed EVENT/EOSE/OK/NOTICE instead of always nil\n- Improves chat receipt of geohash and DM events after Tor readiness 2025-09-11 19:53:19 +02:00
IslamandGitHub 2f83433247 Refactor parsing inbound messages (#577)
* DRY + helper extension to get data from Message

* Flatten guard > do > if > switch + use `try?`

* Use failable init instead of a global function
2025-09-11 19:18:06 +02:00
IslamandGitHub e72fe50ffa Perf: Add final to classes that are not inherited (#574) 2025-09-11 19:17:04 +02:00
IslamandGitHub 56f1c37129 Regenerate info.plist by adding the missing keys (#576)
`xcodegen` probably uses alphabetical sorting so had to commit the info.plist to avoid discrepancies
2025-09-11 19:14:27 +02:00
IslamandGitHub 2ade3a3300 Add TransportConfig to bitchatShareExtension target (#579)
ShareViewController uses TransportConfig and without this target membership the code doesn’t compile
2025-09-11 19:13:54 +02:00
5f44af19da tor by default, small (#564)
* feat(tor): Tor-by-default scaffold and integration

- Add TorManager with static/dlopen start, torrc generation, SOCKS probe
- Add TorURLSession; route Nostr/Web fetches via SOCKS proxy
- Add chat system messages for Tor status; show progress (macOS) and ready
- Disable ControlPort bootstrap monitor on iOS; keep it on macOS
- Make Tor waits non-blocking; avoid main-actor stalls on startup
- Queue & flush Nostr subscriptions on relay connect; skip duplicates
- Always rewrite torrc at launch to fix iOS container path mismatches
- Link libz; add project wiring for tor-nolzma.xcframework
- Minor fixes: SOCKS probe resumeOnce guard, entitlement for network.server (macOS)

* iOS: deterministic Tor recovery + 100% gating; BLE-first; session rebuild

- Restart/wake Tor on foreground via ControlPort (ACTIVE/SHUTDOWN),
  avoid restarts during bootstrap; add NWPathMonitor to trigger checks
- Use NWConnection control polling for GETINFO; remove blocking CFStream
  readers to avoid QoS inversions; compute readiness from SOCKS + 100%
- Rebuild TorURLSession on resume; reset Nostr connections to rebind
- Gate all internet after full bootstrap; keep BLE mesh startup fast
- Fix Swift 6 capture issues; hop UI updates to @MainActor
- Remove Tor progress spam; persist initial "starting tor..." system message

* UI: show Tor system messages only in geohash channels (not mesh)

- Gate "starting tor..." and readiness/timeout messages to geohash view
- Add helper addGeohashOnlySystemMessage() to avoid posting to mesh timeline
- Persist system messages in geohash backing store via addPublicSystemMessage()

* Relays: treat repeated -1011 handshake failures as permanent; skip reconnects

- Classify NSURLErrorBadServerResponse as permanent and stop retrying
- Filter permanently-failed relays from subscribe/connect attempts
- Avoid reconnect scheduling for permanently failed relays

* Embed Tor via tor_api; deterministic restart + Nostr gating; add Tor notifications

- Run Tor via tor_api in a dedicated thread with OwningControllerFD
- Cleanly stop Tor on background; restart on .active (single instance)
- Avoid fallback to tor_main/dlopen; add is-running check to prevent duplicates
- Fix argv lifetime in C glue to avoid strcmp crash on start
- Gate Nostr connect/subscribe/send until Tor is fully ready
- Rebuild URLSession + reset relays after Tor readiness (scene-based)
- Remove TorDidBecomeReady double-reset and appDidBecomeActive resubscribe
- Add TorWillRestart/TorDidBecomeReady notifications and chat system messages
- Debounce path-change restarts; ACTIVE poke first; coalesce subs; cancel stale reconnect timers
- Project: add CTorHost.c and TorNotifications.swift to targets; fix libz.tbd path

* Defer Nostr setup logs until Tor is ready; fix subscribe coalescing and reconnect generation

- Move "Connecting to Nostr relays" log after awaitReady()
- Log "Queuing subscription" when Tor not ready; only coalesce when handler exists
- Clear coalescer on unsubscribe
- Cancel stale reconnect timers using connectionGeneration
- Remove app-level TorDidBecomeReady reset to avoid duplicate reconnects
- Debounce path-change restarts

* Gate Nostr init/subscription logs until Tor is ready

- ChatViewModel: await Tor readiness before initializing Nostr and logging
- Only log GeoDM subscription when Tor is ready to avoid early noise

* Make Nostr connect single-sourced; defer DM subscription until connected

- Remove duplicate connect call from ChatViewModel; let scene-based flow connect
- Setup DM subscription once on first connection via  sink
- Reduce early subscription send/cancel noise after Tor restarts

* On launch, queue Nostr subscriptions without initiating connects; let centralized connect handle it

- In subscribe(), if no connections exist, just list relays and queue subs
- Avoids early send/cancel churn before connect() runs post-Tor-ready

* Always queue subscriptions and flush on connection; avoid immediate sends

- Prevents early send/cancel churn at launch and during reconnects
- If relays are already connected, flush immediately; otherwise pending until connected

* UI: scope Tor restart messages to geohash channels; skip initial foreground restart on cold launch to avoid confusing system message in #mesh

* geo: disable background sampling + notifications\n- Gate sampling to foreground only (beginGeohashSampling, watchers)\n- Suppress geohash activity notifications unless app is active\n- Stop sampling explicitly on background scene phase

* Update BitchatApp.swift

Co-authored-by: asmo <asmogo@protonmail.com>

* Update BitchatApp.swift

Co-authored-by: asmo <asmogo@protonmail.com>

* Update BitchatApp.swift

Co-authored-by: asmo <asmogo@protonmail.com>

* Update bitchat/BitchatApp.swift

Co-authored-by: asmo <asmogo@protonmail.com>

* Update bitchat/BitchatApp.swift

Co-authored-by: asmo <asmogo@protonmail.com>

* fix(iOS App): resolve merge artifacts in scenePhase handler\n- Remove duplicate didEnterBackground state\n- Fix switch/if braces and logic for foreground restart gating

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: asmo <asmogo@protonmail.com>
2025-09-11 19:08:43 +02:00
lollerfirstandGitHub 6e1fb15edf feat: weekly update bundled georelays (#524)
* update bundled georelays

* fix typo
2025-09-11 13:30:33 +02:00
IslamandGitHub 9166c9e28b Update iOS App Icon to the new single-size format (#573) 2025-09-11 11:15:57 +02:00
0ce68bc762 Perf/optimizations (#563)
* Perf: reduce hot‑path overhead (logger autoclosure, zero‑copy BinaryProtocol.decode, prealloc encoders)

* Compression: revert to zlib per request (compatibility)

* Nostr: parse inbound messages off-main, then update state on main; BLE: debounce peer snapshot publishing to reduce churn

* Fix: Swift 6 concurrency - avoid capturing self in detached tasks; deliver parsed Nostr messages via MainActor singleton

* Fix: move ParsedInbound + parseInboundMessage to file scope (non-isolated) to satisfy Swift 6; update detached tasks to call free function

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-09-06 12:47:32 +02:00
5273f13512 Fix critical routing and buffer issues\n\n- Preserve unsent items in MessageRouter outbox (no data loss)\n- Drain and bound Nostr send queue; flush on relay connect\n- Cap BLE pending write buffers per peripheral to avoid OOM\n- Enable Nostr fallback for short peer IDs via favorites mapping\n- Route favorite notifications via MessageRouter (mesh/Nostr) (#559)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-09-04 21:26:58 +02:00
e79bcf531b Feature/screenshot privacy warning (#541)
* Screenshot privacy: warn on location sheet; gate screenshot broadcasts to chat only\n\n- Track sheet presentation in ChatViewModel\n- Show privacy alert when screenshot taken on location channels\n- Ignore screenshots for App Info and Location sheet for broadcast\n- ContentView wires sheet onAppear/onDisappear and presents alert\n- Fix location sheet subtitle wrapping: render as single Text to avoid orphaned bullets

* Fix duplicate messages after channel switch\n\n- Dedup on per-geohash append (skip if ID exists)\n- Dedup and sort timeline by timestamp when switching into a geohash\n- Keep content/layout unchanged; add lightweight debug logs for empty rows

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-28 14:37:17 +02:00
jack 3e5043f875 Harden text formatting against Unicode range mismatches
- Use NSString.length for all NSRange regex scans
- Guard string slicing when lastEnd > match.lowerBound
- Advance lastEnd safely to avoid backtracking overlaps
- Apply to formatMessageContent, formatMessage, formatMessageAsText, parseMentions
2025-08-28 09:22:34 +01:00
jack 11cd5527ed Fix crash in formatMessageAsText: use NSString length for NSRanges and guard slicing before matches to avoid invalid ranges with multi-byte content 2025-08-28 09:18:11 +01:00
cf1bfdac6b Geohash Bookmarks + Rising‑Edge Notifications + Friendly Names (#538)
* Add geohash bookmarks: persistence, sampling integration, and UI\n\n- Add GeohashBookmarksStore with UserDefaults persistence and toggle API\n- Sample union of regional + bookmarked geohashes for activity notifications\n- LocationChannelsSheet: bookmark icons on nearby rows and a Bookmarked section\n- Header toolbar: toggle bookmark for current geohash\n- Tests: GeohashBookmarksStoreTests for normalization and persistence\n\nRationale: Bookmarked geohashes are always sampled for new activity notifications and quickly selectable from the sheet.

* Notifications: remove background 'new chats!' nudge; geohash activity only on zero→alive; mesh 'nearby' only on zero→alive\n\n- Geohash sampling: notify only when previous participant count in last 5m was zero, with 30s freshness gate\n- Suppress old sampled events after (re)subscribe\n- Remove channel inactivity nudge\n- Mesh: reset rising-edge gate immediately when peer list goes empty (strict zero→alive)

* Geohash notifications: ensure triggering message appears\n\n- On zero→alive sampling, pre-populate geoTimelines[gh] with the triggering message\n- Dedup on per-geohash timeline and UI messages by message ID to avoid duplicates after subscribe\n- Keeps participant update, block/self checks, and cooldown intact

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-28 09:10:15 +01:00
b63a595b04 Fix geohash UX: rising-edge notify, correct teleport, sort timeline (#537)
- Remove "new chats!" background nudge; notify only when a regional geohash goes from 0 participants to activity, with content preview and cooldown.\n- Do not mark teleported when selected geohash is in regional channel list; clear persisted teleport when in-region; avoid self teleported state from historical tags; deep links don’t mark teleported for regional geohashes or during cold start.\n- Sort per-geohash timelines chronologically on re-entry and trim whitespace-only content to prevent blank lines.\n- Trim inbound public content and ignore whitespace-only sends.

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-28 00:08:01 +01:00
d7b7f1f673 UI: diversify peer colors; smarter geo notifications; 21m live location (#531)
- Use minimal-distance hue palette for mesh and geohash lists; align chat sender colors with list palette.
- Add foreground geo notifications for different channels; deep-link to bitchat://geohash/<gh>; per-geohash 60s cooldown; respect self/blocks.
- Global geohash sampling runs outside the sheet; delegate handles deeplinks and suppresses when already in-channel.
- Switch location channel sheet to continuous CoreLocation with 21m distance filter; add config knob.
- Only link geohash hashtags when standalone (no @name#abcd or word#abcd).
- Include mesh-reachable peers in mesh counts and in "bitchatters nearby" notification.
- Add TransportConfig knobs for palette and geo notifications.

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-26 18:43:22 +02:00
JDandGitHub 7aa3622349 Update README to explain hybrid messaging architecture (#530) 2025-08-26 18:42:21 +02:00
96c6fc0c0d Improve mesh relaying, presence, and DM robustness; signed public msgs; reachability UI; quicker announces; store-and-forward (#527)
* Sign public broadcasts; verify relayed messages via persisted signing keys; keep scheduled relays in sparse graphs and speed their jitter; persist announce signing key for offline auth; add short backoff after disconnect errors to reduce reconnect thrash

* Add connected vs reachable model: retain peers after link drop, expire after reachability window; expose all peers in snapshots; compute isReachable in UI; add meshReachable state and sorting; avoid removing peers on link events; notify UI on stale removals

* ContentView: handle new .meshReachable connection state in header icon switch (exhaustive switch fix)

* Logs: tag relayed announces as 'Reachable via mesh' and annotate public message logs with (direct|mesh) path for easier field analysis

* Fix syntax error: remove stray else/log inserted into writeOrEnqueue; keep logs clean

* UI: use 'point.3.connected.trianglepath.dotted' for mesh-reachable; change people count to include connected+reachable (exclude Nostr-only)

* UI: switch to 'point.3.filled.connected.trianglepath.dotted' for mesh-reachable icons in list and header

* Reachability: reduce retention to 21s for all peers (verified and unverified) to minimize stale presence

* mesh DMs/acks: route to reachable peers; queue READ/DELIVERED until handshake; add Transport.isPeerReachable; UI: hide offline non-mutuals; DM header: better name fallback + show transport + encryption icons; fix NostrTransport conformance

* Verification sheet: compute encryption status and fingerprint using short mesh ID mapping (fix 'not encrypted/handshake' for DMs with stable key)

* Announce cadence: faster discovery (4s), sparse 15±4s, dense 30±8s; initial 0.6s; post-subscribe 50ms; min-force 150ms; maintenance 5s; proactive announces on handshake + recent-traffic nudge

* Relay: increase broadcast TTL cap in sparse graphs to 6; tighten jitter for handshake (10–35ms) and directed (20–60ms) relays

* Range/robustness: store-and-forward for directed packets (15s) with flush on new links + periodic; announces: no subset + afterglow re-announce on first-seen; adaptive scanning: force ON when <=2 neighbors or recent traffic

* Fix warnings: remove unused msgID and unused mutable var in directed spool flush

* Announces: TTL 7 (sparse only) via RelayController; no fanout subset for announces; neighbor-change rebroadcast of last 2–3 announces. Fragments: faster pacing (5ms global, 4ms directed).

* Peer list: real-time icon updates by publishing snapshots on connectivity checks; add unread message indicator (envelope) next to peers with unread DMs

* UI: unread envelope uses orange; hasUnreadMessages checks Nostr conv key for peers with known Nostr pubkeys (geohash DM consistency)

* Logs/robustness: debounce disconnect notifications (1.5s), debounce 'reconnected' logs (2s), add weak-link cooldown after timeouts on very weak RSSI (<= -90)

* Peer icons: faster, accurate reachability\n\n- Run connectivity checks every maintenance tick (5s)\n- Publish peer snapshots on central unsubscribe for instant UI refresh\n- Lower inactivity timeout to 8s and disconnect debounce to 0.9s\n- Gate reachability on mesh-attached (>=1 direct link); no links => no reachable peers\n- Keep 21s retention for verified/unverified, but only when attached to mesh\n\nImproves list responsiveness when walking out of range and prevents stale 'reachable' states when isolated.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-26 17:28:08 +02:00
a7d5b2d7d9 Centralize remaining magic numbers; finalize logging hygiene across UI/BLE/Nostr (#522)
* docs(plans): add refactor plan; chore(config): introduce TransportConfig and use in BLEService/ChatViewModel/PrivateChatManager; feat: add PeerDisplayNameResolver and apply in BLEService; chore: make TransportPeerSnapshot Equatable/Hashable; perf: simplify read-receipt persistence (no synchronize)

* project: add TransportConfig.swift and PeerDisplayNameResolver.swift to iOS/macOS targets (no xcodegen)

* chore: remove unnecessary UserDefaults.synchronize() calls (extension/app/VM)

* project: fix TransportConfig reference path; remove recovered reference; hook correct fileRef in iOS/macOS sources

* chore(BLE): move connect/duty/announce constants to TransportConfig and reference them

* chore(NostrTransport): factor recipient npub resolution into helper; reduce duplication

* chore(BLE): trim raw hex dump on central decode failure to length+prefix

* project: remove duplicate TransportConfig.swift entries from Sources build phases

* chore: centralize more constants in TransportConfig (BLE thresholds, Nostr read-ack, UI caps) and adopt in BLEService/ChatViewModel/NostrTransport

* chore: centralize location + geohash constants (filters, lookback, relay count) and adopt in LocationChannelManager/ChatViewModel

* chore: centralize compression, dedup, verification QR, relay backoff, georelay fetch constants; adopt across modules

* chore: centralize more BLE/Nostr delays; tighten NostrRelayManager logs to concise summaries; adopt config for location/geohash/relays

* refactor(config): centralize remaining magic numbers and finalize log hygiene

Add comprehensive TransportConfig constants for UI, Nostr, and BLE; adopt across ChatViewModel, ContentView, BLEService, ShareViewController, and BitchatApp to remove scattered literals. Standardize Nostr lookbacks/limits, UI delays/animations, and BLE announce/duty-cycle/candidate caps. Preserve behavior while making tuning explicit and safe.

Highlights:\n- UI: animations, scroll throttle, long-message thresholds, batch stagger, color hue tuning, rate-limit buckets, read-receipt debounce, startup delays, share accept/dismiss windows, migration cutoff.\n- Nostr: short display length (8), conv-key prefix length (16), DM lookback (24h), geohash sample lookback/limits; consistent use throughout ChatViewModel.\n- BLE: dynamic RSSI defaults, announce intervals/base+jitter, duty cycles (dense/sparse), fragment/ingress lifetimes, expected write timings/spacing, recent packet window (30s/100), peer inactivity timeout; unified candidate caps (100).\n- Share: use constant dismiss delay; App: use constant share accept window.\n\nRisk/impact: behavior-equivalent with centralized knobs; easier to tune without code edits.

* project: add TransportConfig.swift to Share Extension target to fix build

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-25 21:18:51 +02:00
680a390b2d Nostr: sign events directly with Schnorr keys; update call sites to use Schnorr and remove temporary Signing.PrivateKey conversions (#521)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-25 18:31:53 +02:00
60b0deee7b Cleanup: remove dead code, normalize fingerprints, modernize share extension, trim test noise, and drop ‘preparing to share…’ message (#520)
* Remove dead code and artifacts: drop PeerManager, unused views/types; delete LegacyTestProtocolTypes; update .gitignore; purge TestResult.xcresult and build.log

* Tests: gate verbose prints under DEBUG; ChatViewModel: remove legacy fingerprint helper and rely on UnifiedPeerService

* Share Extension: migrate to UIKit + UTTypes; drop Social/SLComposeServiceViewController

* Remove 'preparing to share …' system message; send shared content immediately

* Inline comment cleanup: drop legacy 'removed' breadcrumbs across protocols, services, view model, and views

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-25 18:01:19 +02:00
jackandGitHub 2f7c0aaaf7 Delete TestResult.xcresult directory 2025-08-25 16:36:36 +02:00
7c4c3f1391 macOS geohash parity: shared LocationChannelsSheet with permission CTA, enable CoreLocation on macOS, unify geohash participants/DMs, update ContentView (unread + QR on macOS), commands: hide/block /fav & /unfav in geohash, remove /help, make /who show geohash participants, fix ViewBuilder mutation+sheet toolbar, entitlements for mac location (#519)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-25 16:29:52 +02:00
3c06bd6386 Improve BLE mesh flooding: last-hop suppression, K-of-N fanout, and backpressure (#517)
* Improve BLE mesh relay and flooding

Add last-hop suppression using ingress-link tracking to prevent echo. Implement deterministic always-relay for handshakes and directed encrypted/fragments; widen jitter for broadcasts; keep TTL cap only for broadcast. Add deterministic K-of-N broadcast fanout to reduce amplification in dense topologies. Introduce backpressure-aware writes using canSendWriteWithoutResponse with per-peripheral queues and draining on peripheralIsReady. Minor helpers for messageID, deterministic selection, and maintenance cleanup.

* Tests: stabilize FragmentationTests and InputValidatorTests

Make _test_handlePacket mark synthetic peers verified/connected with normalized senderID to avoid drops in public-message reassembly tests. Tighten validatePeerID to reject non-hex strings when length equals 16 or 64; allow internal IDs only for other lengths. All iOS simulator tests pass locally.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-25 11:51:50 +02:00
jack acc11101ad Fix geohash linking: avoid links in @mentions
Only link #geohash tokens when not directly attached to an @mention (e.g., @name#gh stays plain). Keeps standalone #geohash tappable.
2025-08-25 09:31:41 +02:00
5fd9140ffa QR verification: live challenge/response over Noise; persistence, offline badges, and UX/perf polish (#510)
* QR verification scaffold: add Noise verify payload types, VerificationService with QR schema/signing, placeholder MyQR/Scan views, and UI entry points in header

* QR: fix VerificationQR mutability (sigHex var) and remove duplicate Data hex helpers to resolve redeclaration; wire signed payload assembly

* QR: render actual QR images with CoreImage; add copy button; keep scanner placeholder for now

* QR: fix SwiftUI modifiers — apply .interpolation(.none) and .resizable() to platform Image inside ImageWrapper; remove from wrapper usage

* QR: add iOS camera scanner using AVFoundation; integrate into Scan view; add NSCameraUsageDescription to Info.plist

* QR: make NoisePayloadType exhaustive in ChatViewModel switches by ignoring verifyChallenge/verifyResponse for now (placeholder)

* QR verification: speed + persistence + UX

- Inject live Noise into VerificationService; prewarm QR on app start
- Keep camera active; remove intermediate responder toast
- One-shot/dupe guards and deferred send on handshake
- Persist verified status immediately; standardize fingerprint (SHA-256)
- Show verified badge for offline favorites; mutual verification toast
- VERIFY sheet styling to match peer sheet; UI polish
- Logs to diagnose verified load + favorites mapping

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 23:19:58 +02:00
e6903456ab NIP‑17/44: XChaCha20 v2 gift wraps, DM kind=14, receipts + UI fixes (#506)
* NIP-17/44: adopt NIP-44 v2 (XChaCha20-Poly1305, v2: base64url), switch rumor kind to 14, randomize BIP-340 aux; add XChaCha20Poly1305Compat and wire-up

* Nostr DMs: ensure delivered/read acks are sent even without Noise key mapping by falling back to direct Nostr (geohash-style) acks to sender pubkey

* NIP-44 v2 decrypt: try both Y parities for x-only sender pubkeys (even then odd) to fix unwrap authentication failures

* Tests: add NIP-44 v2 ACK round-trip tests (delivered/read) using bitchat1 embedding and gift-wrap decrypt path

* UI: fix DM autoscroll IDs by using dm:<peer>|<id> for private chat item IDs and preserve anchors, ensuring scrollTo targets exist when opening/switching/new messages

* UI: fix string interpolation in DM/geohash context keys (remove escaped interpolation) to resolve 'unused ch' warnings and ensure proper IDs

* UI: MeshPeerList shows transport state icon: radio for mesh-connected, purple globe for mutual favorite/Nostr; fallback dim person for others

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 17:56:43 +02:00
85f99984c4 Unify DM notifications and fix geohash self-echo hydration (#505)
* feat(notifications): unify DM notifications across transports; notify for unread+recent even in foreground; delegate suppresses if chat open

* fix(geohash): include own past geohash messages on channel load; skip only very recent self-echo (<15s) to avoid duplicates

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 14:40:06 +02:00
75c8933091 Feat/georelay (#504)
* feat(georelay): route geohash kind 20000 via nearest relays; add GeoRelayDirectory; target geohash subscriptions; avoid duplicate connections

* feat(georelay): fetch daily from remote CSV with fallback to bundled; cache to app support; prefetch on app load

* fix(georelay): make CSV parser nonisolated and call as Self.parseCSV to satisfy Swift 6 actor isolation

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 12:49:52 +02:00
d2bfbbcfd4 Fix/chat perf (#502)
* perf(chat): batch public inserts, sort batch by ts; add per-sender + per-content token buckets; content-based near-dup suppression; reuse compiled regexes; single token scans per row; disable list animations during batches

* perf(chat): conditional animations via isBatchingPublic; late-arrival binary insert; flush public buffer on channel switch; prewarm formatting on flush

* perf(chat): batching, spam rate-limits, near-dup LRU, adaptive flush, faster trims, regex/detector reuse, conditional animations, late-insert, current-mode prewarm, Swift 6-safe timer/closures

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 11:11:49 +02:00
0260798712 Fix/UI (#500)
* Remove link previews: link URLs inline\n\n- Delete LinkPreviewView and all references\n- Strip preview usage from ContentView\n- Make detected URLs tappable via .link attribute\n- Add MessageTextHelpers for tokens/length checks\n- Wire helpers into iOS/macOS targets

* Peer list UX: match message colors, use map pin icon, stable ordering\n\n- Color list names and icons with same peer color as messages\n- Default icon mappin; teleported uses face.dashed (iOS)\n- Geohash: move teleported peers to bottom\n- Maintain stable order: append new peers, remove missing\n- Mesh list: replace state icons with colored mappin/person

* Fix peer list build errors: remove ambiguous Set type, avoid guard in ViewBuilder, remove duplicate bindings, and simplify person lookup

* Peer list: remove onChange expressions to avoid type-check issues; rely on ObservedObject updates

* Peer lists: simplify view structure to satisfy SwiftUI type checker (replace Group with VStack, flatten body)

* Peer lists: move ordering mutations to onAppear/onChange, keep body pure; fix result builder errors

* Fix: remove trailing modifiers outside if/else to avoid ViewBuilder type issues

* Color parity: fix seed cache to include color scheme; normalize Nostr seeds; switch to mappin.circle icon

* Peer colors: ensure exact match with message colors\n\n- Mesh list uses same seed logic as messages (getNoiseKeyForShortID fallback)\n- Color cache keyed by theme; normalize nostr seeds\n- Icons: use mappin.and.ellipse (default) and face.dashed for teleported\n- Teleport tag: accept "teleported" in addition to "teleport" and presence events

* Fix geohash color mismatch: populate nostrKeyMapping before building messages in resubscribe; also honor t,teleport tag for teleported state

* Message actions: username tap opens sheet via clickable AttributedString; message tap inserts @mention; rename to 'direct message'

* Cashu UX: suppress 'Show more' when message contains a Cashu token (chips handle rendering)

* Cashu detection: broaden regex (allow '.') + shorter min length; avoid long-text fallback when Cashu present so chips render and no full blob

* Geohash levels: rename region->province, country->region; update labels, precision, UI, manager mapping, tests; add Codable backward-compat for renamed cases

* Fix braces in LocationChannel.swift: close enum before extension to satisfy file-scope declarations

* Geohash links: make #geohash tappable and open that channel (bitchat://geohash/<gh>); handle in ContentView.onOpenURL with validation and selection

* Underline tappable #geohash mentions for clarity

* Geochat: sanitize timeline on channel switch to remove any blank-content entries (prevents blank rows)

* Xcode project: sync sources after UI changes (remove LinkPreview, add helpers, update build refs)

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-24 02:05:02 +02:00
jack 2758afa126 ux(chat): scroll to bottom on geohash open; add infinite scroll up with stable anchor; track window size per chat 2025-08-22 19:01:29 +02:00
jack 2229a28bb4 perf(chat): reduce rendering cost and improve stability for large chats\n\n- Window last 300 messages (up from 100) while keeping timeline cap at 1337+\n- Remove .textSelection from message rows to avoid expensive layout\n- Limit link previews per message to 2\n- Keep deferred autoscroll and channel-aware IDs for smooth scrolling 2025-08-22 18:56:26 +02:00
dadc896ed8 Fix/geohash blocks (#483)
* fix(geo-block): enable block/unblock for geohash users and enforce blocks\n\n- Add persisted set of blocked Nostr pubkeys in SecureIdentityStateManager\n- Check Nostr blocks for incoming messages (public + geo DMs)\n- Prevent sending geo DMs to blocked users\n- Extend /block and /unblock to resolve geohash display names to pubkeys and act accordingly\n- Improve /block list to show geohash blocks (visible names or #suffix)

* fix(geo-block): enforce blocks on geohash public and DM receive; add block/unblock actions to geohash people list

* fix: mark handlePublicMessage as @MainActor to call isMessageBlocked safely

* ui(block): show blocked indicator (nosign icon) next to blocked peers in mesh and geohash lists

* fix(geo-block): early-drop blocked pubkeys on geohash receive; filter blocked users from participants list

* fix(geo-block): purge existing geohash messages/DMs on block; block directly from chat using Nostr sender ID when available

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-22 18:44:11 +02:00
b2504a7ff5 Feat/b links (#481)
* feat(cashu): auto-link cashu tokens in chat

- Detect cashuA/cashuB tokens via regex and render as tappable links
- Style like URLs (underline; blue for others, orange for self)
- Add openURL handler for cashu: scheme to delegate to wallet on iOS
- Respect existing heavy-content gating and long-message collapsing

* feat(ln): auto-link Lightning invoices and LNURL + lightning: scheme\n\n- Detect BOLT11 (lnbc/lntb/lnbcrt...), LNURL bech32, and lightning: URIs\n- Render as tappable links with lightning: scheme; consistent styling\n- Handle lightning: in openURL alongside cashu:

* feat(links): replace raw Cashu/Lightning tokens with compact chips (🥜 pay via cashu /  pay via lightning) while keeping them tappable

* style(links): add subtle background highlight to cashu/lightning chips

* ui(links): render Lightning/Cashu as rounded chips under message with padding; remove inline chip text

* ui(links): increase chip padding and corner radius; add extra top padding for chip row

* scroll: auto-scroll to bottom when sending a new message (public + private), regardless of current scroll position

* scroll(geo): when switching geohashes, scroll to top of chat (first visible message)

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-22 17:20:26 +02:00
7f2cbd6621 chat: fix blanking and gaps when switching geohashes; channel-aware row IDs + deferred autoscroll\n\n- Add channel-aware UI IDs (mesh|id, geo:<gh>|id, dm:<peer>|id) to prevent SwiftUI reuse gaps\n- Defer scrollTo to next runloop for stability; auto-scroll on appear/switch\n- Collapse very long messages with Show more/less; skip heavy parsing for huge content\n- Simplify LazyLinkPreviewView (remove GeometryReader in list) (#480)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-22 16:38:40 +02:00
jack 60a42ffecb Merge feature/peer-colors: per-peer colors, mention action, teleport persistence + logs, geohash count consistency, scroll gating, hashtag styling, copy message context menu 2025-08-22 13:08:15 +02:00
jack 27e5e2962c Scroll: move bottom detection to View state and pass Binding to messagesView; autoscroll only when bound is true to prevent jumps when user scrolled up 2025-08-22 13:04:56 +02:00
jack 9d5105a8bf Geohash list: gate empty/render using visibleGeohashPeople() so header count and list visibility are consistent 2025-08-22 13:02:34 +02:00
jack d4b779080a Fix header string interpolation: simplify accessibilityLabel to avoid unterminated string; use '\(headerOtherPeersCount) people' 2025-08-22 12:58:08 +02:00
jack 4bfe9ac80d Geohash count: use the same pruned/sorted list for toolbar and peer list (visibleGeohashPeople) to ensure consistency 2025-08-22 12:51:40 +02:00
adffe7dfd6 Feature/peer colors (#476)
* Feature: assign stable per-peer colors (non-self) across mesh/geohash/DM; keep self orange and mentions-to-me orange; cache colors

* Fix compile warnings: remove unused primaryColor in formatMessageAsText; remove unused CryptoKit import; mark peerColor/formatMessageAsText @MainActor to call main-actor helpers

* Fix: re-import CryptoKit for SHA256 usage in ChatViewModel

* Peer lists: apply same per-peer colors as chat (self orange); suffix uses lighter variant; geohash uses Nostr pubkey, mesh uses Noise key

* Fix warning: remove unused peerNicknames in MeshPeerList

* UI: add 'mention' action in message actions to prefill input with @nick#abcd and focus input

* UX: long-press a message to prefill @mention with sender's full nick#abcd and focus input

* UX: remove long-press mention; add context menu 'Copy message' that copies only the message body (no nick/timestamp)

* Geo teleported: robust tag detection (accept 't', 'teleport', and boolean-like values); mark self on send when tagging; should fix peer list icons

* Logs: add GeoTeleport diagnostics (incoming tags, self/peer marking, counts) to debug peer list dashed icon behavior

* Teleport persistence: store per-geohash teleported state in UserDefaults; initialize on startup; OR with location-derived status; sheet writes persisted flag on select/teleport

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-22 12:41:26 +02:00
jack 16fdb7b49e Teleport persistence: store per-geohash teleported state in UserDefaults; initialize on startup; OR with location-derived status; sheet writes persisted flag on select/teleport 2025-08-22 12:34:44 +02:00
jack ff5fd3f3fe Logs: add GeoTeleport diagnostics (incoming tags, self/peer marking, counts) to debug peer list dashed icon behavior 2025-08-22 12:29:23 +02:00
jack f8a955214b Geo teleported: robust tag detection (accept 't', 'teleport', and boolean-like values); mark self on send when tagging; should fix peer list icons 2025-08-22 12:24:17 +02:00
jack d5e712e27f UX: remove long-press mention; add context menu 'Copy message' that copies only the message body (no nick/timestamp) 2025-08-22 12:18:33 +02:00
jack 244c8cdf81 UX: long-press a message to prefill @mention with sender's full nick#abcd and focus input 2025-08-22 12:13:59 +02:00
jack 0d064084aa UI: add 'mention' action in message actions to prefill input with @nick#abcd and focus input 2025-08-22 12:12:49 +02:00
jack 7b49268694 Fix warning: remove unused peerNicknames in MeshPeerList 2025-08-22 11:51:17 +02:00
jack 5650e1f2c2 Peer lists: apply same per-peer colors as chat (self orange); suffix uses lighter variant; geohash uses Nostr pubkey, mesh uses Noise key 2025-08-22 11:49:44 +02:00
jack c4b422ad3f Fix: re-import CryptoKit for SHA256 usage in ChatViewModel 2025-08-22 11:47:21 +02:00
jack e82fda1093 Fix compile warnings: remove unused primaryColor in formatMessageAsText; remove unused CryptoKit import; mark peerColor/formatMessageAsText @MainActor to call main-actor helpers 2025-08-22 11:45:49 +02:00
jack 806d451135 Feature: assign stable per-peer colors (non-self) across mesh/geohash/DM; keep self orange and mentions-to-me orange; cache colors 2025-08-22 11:43:44 +02:00
13f8b0c636 Fix/geohash work (#475)
* Scroll UX: auto-scroll only when last item visible; preserve user position when scrolled up for mesh/geohash/DM; reduce blanking after very long messages

* iOS: re-enable keyboard autocomplete and default capitalization for message input

* Styling: stop blue/underline styling for #hashtags; render as normal text color (self=orange, others=green)

* Geo UI: ensure self shows teleported (face.dashed) if either per-session tag or manager flag is true

* Geo teleported: publish UI updates by assigning @Published Set instead of in-place insert; update on tag receipt and channel switch

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-22 11:38:44 +02:00
2014andGitHub 2d0f9aff0a fixed quote and period (#471)
moved period outside quotes for consistency, as appears elsewhere.
2025-08-22 01:18:46 +02:00
83ee5abb60 Fix: stabilize per-geohash identity seed by storing in Keychain with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly and caching in memory to avoid transient regenerations (#473)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-22 01:05:44 +02:00
bc27e16899 Fix/visuals (#469)
* Geohash peers: show face.dashed for self when channel selected via teleport; face.smiling otherwise

* Geo presence: broadcast 'teleport' tag on geochat join; track teleported participants and show face.dashed for them in peer list

* Teleport tag: attach to actual geohash chat events (sendMessage, emotes, screenshots) instead of separate presence; remove presence emit

* Fix: show face.dashed for any teleported peer (not just self) in geohash list

* Geo list: show self immediately on channel switch and mark teleported state; clear teleported flags on leaving geochat

* Teleport persistence: recompute teleported based on current location vs selected geohash; add face.dashed icon to Teleport button label

* Styling: use lighter green/orange for #abcd suffix after nicknames in all chats (senders and @mentions)

* Peer lists: render #abcd suffix as lighter green/orange (self orange) in geohash and mesh lists

* Toolbar: move unread icon next to #channel badge and allow dynamic width; Peer lists: increase top spacing before first item

* Toolbar: prevent geohash channel badge from truncating; give it layout priority and fixed width

* Toolbar: make unread envelope independent from channel button (sits left of badge); fix accidental taps opening channel selector

* Toolbar: make unread envelope open most recent unread/private chat directly

* Geohash peer list: render self row fully orange (icon, base, suffix, '(you)')

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-21 11:15:18 +02:00
jack d3d9a22757 Mentions: color @mentions orange only when directed at me; otherwise use normal color (respect geohash suffix) 2025-08-21 03:26:46 +02:00
jack 8a269d4fec UI: grey #abcd suffix in geohash peer list; keep base name (and '(you)') styled normally 2025-08-21 03:02:42 +02:00
jack 33fbca67d6 UI: render self-authored messages in orange (sender and content); keep links/hashtags orange for self 2025-08-21 03:01:14 +02:00
jack c63350a4d3 UI: bold entire message text for self in mesh, DM, and geohash; adjust caching to include self flag 2025-08-21 02:51:14 +02:00
jack 222854c60a UI: rename AppInfoView toolbar button to 'close' for consistency 2025-08-21 02:45:20 +02:00
jack c624611e7d Merge fixes/location-channels into main: resolve LocationChannelsSheet conflict (retain title bolding only) 2025-08-21 02:23:03 +02:00
jack eb0debd52a Fix: route /hug and /slap to active public channel using sendPublicRaw (geohash when selected) 2025-08-21 01:59:47 +02:00
jack 916f535503 Fix: send screenshot notice to active public channel (geohash when selected), not always mesh 2025-08-21 01:52:54 +02:00
jack de39ab6687 UI: stop bolding location subtitle names; only bold the channel label when count > 0 2025-08-21 01:18:44 +02:00
a0a973eb81 Fixes/location channels (#465)
* Remove "street" location channel; add coverage + names; style mesh

- Drop GeohashChannelLevel.street and update mappings/tests\n- Map geohash lengths >=8 to Block in teleport, no Street\n- Show ~distance coverage (mi/km via Locale.measurementSystem) next to each #geohash\n- Add reverse geocoding to display coarse names (country/region/city/neighborhood) per level\n- Style "#mesh" row title with toolbar blue\n- Fix iOS 16 deprecation: use Locale.measurementSystem

* Project: update Xcode project (auto)

* UI: use '~' without trailing space before location name in sheet

* Location sheet: poll for location at regular intervals while open (replace significant-move updates)

* UI: show Bluetooth range next to #bluetooth in location sheet

* UI: remove leading '#' from mesh title in location sheet

* UI: bold location name in sheet when geohash has >0 people; refactor row to render subtitle pieces

* UI: bold mesh/level titles when participant count > 0; factor meshCount()

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-21 01:01:29 +02:00
jack ba1dd100ec UI: bold mesh/level titles when participant count > 0; factor meshCount() 2025-08-21 00:56:29 +02:00
jack 97b1463b30 UI: bold location name in sheet when geohash has >0 people; refactor row to render subtitle pieces 2025-08-21 00:54:14 +02:00
jack 28c87a41c1 UI: remove leading '#' from mesh title in location sheet 2025-08-21 00:51:18 +02:00
jack 68c61476d8 UI: show Bluetooth range next to #bluetooth in location sheet 2025-08-21 00:49:12 +02:00
jack 602e93d1b2 Location sheet: poll for location at regular intervals while open (replace significant-move updates) 2025-08-21 00:46:53 +02:00
jack e7706fc9cb UI: use '~' without trailing space before location name in sheet 2025-08-21 00:44:37 +02:00
jack f30677403f Project: update Xcode project (auto) 2025-08-21 00:41:28 +02:00
jack b4fcea2672 Remove "street" location channel; add coverage + names; style mesh
- Drop GeohashChannelLevel.street and update mappings/tests\n- Map geohash lengths >=8 to Block in teleport, no Street\n- Show ~distance coverage (mi/km via Locale.measurementSystem) next to each #geohash\n- Add reverse geocoding to display coarse names (country/region/city/neighborhood) per level\n- Style "#mesh" row title with toolbar blue\n- Fix iOS 16 deprecation: use Locale.measurementSystem
2025-08-21 00:34:17 +02:00
jack 43166bcd64 iOS: keep mesh alive in background; remove stopServices() on scenePhase .background so incoming messages can still arrive and trigger notifications. 2025-08-20 18:09:57 +02:00
496972dcc9 Mesh robustness optimizations (#463)
* Mesh robustness: link-aware fragmentation, relay jitter, connection budget, adaptive scanning; fix BLE queue deadlock

- Link-aware fragmentation using per-link write/notify limits
- Directed fragments for one-to-one; exclude from relays
- Add relay jitter with cancel-on-duplicate to reduce floods
- Cap central links and rate-limit connect attempts with queue
- Foreground duty-cycled scanning when connected; continuous when isolated
- Fix deadlock by avoiding sync on BLE queue when already on it
- Silence Keychain var->let warnings

* Mesh: add relay jitter; dynamic RSSI threshold; candidate scoring/backoff; fix misplaced lines in BLEService extension

* macOS UI: restore mesh peer list when geohash feature is iOS-only by moving mesh list outside iOS switch (ContentView)

* ContentView: add macOS mesh peer list under #else to fix missing People section on macOS

* Refactor People section: extract MeshPeerList and GeohashPeopleList into separate views to reduce SwiftUI type-checking complexity; integrate in ContentView

* BLE: prevent re-fragmentation loops; UI: darker mesh blue + first-row spacing in peer list

* Mesh flood/battery: probabilistic relays, adaptive TTL caps, fragment pacing + scan pause, assembly cap; enable relayed DMs with direct-first then flood fallback.

* Refactor BLEService broadcast: split pad policy, encrypted/direct-first handler, and link-aware sender; simplify broadcastPacket to delegate by type.

* Extract relay decision into RelayController with RelayDecision; simplify handleReceivedPacket to use it.

* Move RelayController and RelayDecision into their own file under Services; keep BLEService leaner.

* UI: adjust mesh blue to a darker, less purple tone; apply consistently for count and #mesh badge.

* Project: include RelayController.swift in target and sync project file changes.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-20 16:27:49 +02:00
3074fa0fcb Refactor/repo hardening 01 (#462)
* BinaryProtocol: add optional padding control; BitchatPacket API for padded/unpadded bytes; BLEService: use unpadded encoding and remove ad-hoc unpadding on BLE writes

* BLEService: balance BLE padding — pad Noise handshake/encrypted frames; leave public/announce/leave unpadded; keep fragmentation consistent with chosen padding

* BLEService: replace Timer with DispatchSourceTimer on bleQueue; NostrTransport: cache placeholder NoiseEncryptionService to avoid reallocation

* Unify peerID validation: InputValidator handles 16-hex, 64-hex, or alnum-/_; NoiseSecurityValidator now delegates to InputValidator

* UI: use standard green for geohash toolbar badge and count (less bright in light mode)

* UI: standardize geohash sheet green to app standard (dark: system green, light: darker green) for buttons and checkmark

* Docs: align BinaryProtocol compression docs to zlib; Logs: reduce NostrTransport DELIVERED ack logs to debug to cut noise

* Tests: add InputValidator peerID coverage and BinaryProtocol padding round-trip/length tests

* Project: ensure Xcode project reflects new tests (references added)

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-20 13:29:53 +02:00
jack bdbcbb5d2b Remove unused getPeers(): use Transport.getPeerNicknames() instead 2025-08-20 12:15:05 +02:00
jack ed4d8b667e Remove stale message-type whitelist from InputValidator: rely on MessageType/NoisePayloadType at decode to prevent drift 2025-08-20 12:15:05 +02:00
jack a29f517783 Harden Keychain access-group usage: avoid -34018 without entitlements; fallback to no access group on macOS/simulator; retry without group on iOS 2025-08-20 12:15:05 +02:00
jack 78917fa7c9 BLE announces: delay after subscribe, queue announce on notify buffer full, and raise announce throttle (min interval + forced min) 2025-08-20 11:54:43 +02:00
jack eb16d128f2 BLE: avoid self-message drop warnings by pre-marking own public broadcasts in dedup and ignoring self-origin public packets 2025-08-20 11:37:47 +02:00
b09710a7aa Feature/location channels (#459)
* Require signed announces; add Ed25519 key/signature/timestamp TLVs and verify

- Protocol: AnnouncementPacket now requires ed25519PublicKey (0x03), announceSignature (0x04), and announceTimestamp (0x05). Encoder emits, decoder requires; unknown TLVs still tolerated.
- NoiseEncryptionService: add canonical announce sign/verify helpers using context 'bitchat-announce-v1'.
- BLEService: sign Announce, include TLVs; on receive verify (±5 min skew) and ignore unverified; store ed25519 key and isVerifiedNickname in PeerInfo.
- Preserve 8-byte on-wire IDs to keep BLE headers small; no per-message bloat.

* Fix Data.append usage for timestamp bytes in Packets and NoiseEncryptionService (use append(contentsOf:) on UnsafeRawBufferPointer)

* BLEService: fix non-optional announce fields and unwrap signature result; enforce required verification path

* Enforce verified-only public messages; append peerID suffix on nickname collisions in handleMessage

* Suffix duplicate nicknames with peerID prefix in snapshots and getPeerNicknames; ensures lists and messages disambiguate 'jack' vs 'jack'

* Include self nickname in collision detection: suffix remote 'jack' when it matches our nickname in lists and public chat

* UI labels: remove space before '#abcd' suffix in names (public chat, peer lists, snapshots)

* Style '#abcd' suffix light gray:
- Public chat: color suffix in sender via AttributedString segments
- People list: split name and color suffix segment; add helper splitNameSuffix()

* Debounce 'bitchatters nearby' notification: add 60s grace before reset when mesh goes empty; cancel reset when peers return

* Lighten '#abcd' suffix: use Color.secondary.opacity(0.6) in public chat sender and People list

* Toolbar peers indicator: use blue when Bluetooth peers present (was default text color)

* Toolbar peers indicator: use grey when zero peers (was red)

* Toolbar peers indicator: use system grey (Color.secondary) when zero peers, not green

* Fix crash: mutate peripherals dict on BLE queue (not main). Move scan restart to BLE queue as well.

* Reduce connect timeout churn: back off peripherals that time out (15s), increase timeout to 8s, skip non-connectable adverts, and demote timeout log to debug; clean backoff map periodically

* Mentions: support '@name#abcd' disambiguation; filter hashtag/URL styling inside mentions; deliver notifications only to the specified suffixed target when collisions exist

* Fix string interpolation in mention log (escape sequence)

* Mentions: parse '@name#abcd' in sender/receiver; render mention suffix grey (not orange/blue/underlined); ensure receiver notifications trigger for suffixed tokens

* Mentions: include own suffixed token 'name#<myIDprefix>' in valid tokens so '@name#abcd' to self is recognized and notified

* Public actions: show own system message by processing own public messages (remove early-return). Private /hug: add local system message for sender's chat.

* Grammar: change local '/hug' message to past tense ('you hugged/slapped'). Notifications: only fire 'bitchatters nearby' on rising-edge; remove 5-min re-fire and increase empty reset grace to 10m.

* Public /hug echo: add local system message so sender sees action immediately (no reliance on echo)

* Fix visibility: expose addPublicSystemMessage on ChatViewModel and use it from CommandProcessor

* Implement iOS Location Channels (geohash public chats)

- Domain: add ChannelID, GeohashChannel(Level), lightweight geohash encoder
- Identity: derive per-geohash Nostr keys (HMAC-SHA256 device seed)
- Nostr: kind 20000 + #g tag, nickname tag (n), filter helper
- iOS: LocationChannelManager (permissions, one-shot location), Info.plist string
- UI: toolbar # badge (#mesh or #<level>), sheet (irc style, full-row taps, settings link)
- VM: subscribe/send for active channel, clear timeline on switch, nickname cache
- Emotes: route public via Nostr/mesh without echo, local system confirmation, emojis restored
- Haptics: detect hugs/slaps for nickname#abcd and trigger on receiver
- Rendering: remove hashtag/mention formatting (plain monospaced)

Note: iOS-only; macOS unaffected.

* Lifecycle and persistence: resubscribe on foreground/relay connect, cap dedup set, persist mesh timeline.

- ChatViewModel: resubscribe geohash on app foreground and relay reconnect
- Add processed Nostr events cap (2k) with eviction
- Persist mesh public messages in meshTimeline; hydrate on switching to #mesh
- Local geochat messages use nostr: senderPeerID for classification
- Tests: fix JSON contains assertion for #g tag

* Fix Swift 6 concurrency warnings: remove closure-based NC observer, wrap relay reconnect resubscribe in Task @MainActor, resubscribe in appDidBecomeActive selector.

* Location Channels polish: live geohash refresh while sheet open; keep selection stable; toolbar shows #<geohash>; sheet labels show human level + #geohash.

* Add per-geohash in-memory timelines and cap private chats to 1337.

- ChatViewModel: persist geohash messages in geoTimelines[geohash] with cap; hydrate timeline on channel switch
- PrivateChatManager: trim per-peer chats to 1337 on send/receive
- Toolbar badge: prevent wrapping with lineLimit(1)/truncation

* Toolbar badge layout + brand color; Teleport custom geohash; Live refresh uses startUpdatingLocation with significant distance.

- Toolbar: right-justify geohash, head truncation, use brand green
- Sheet: add #custom geohash textfield + join; keep minimal IRClike style
- Manager: startUpdatingLocation()/stopUpdatingLocation() with distanceFilter=250 while sheet is open

* Location sheet live updates: reduce distanceFilter to 21m for more frequent geohash refreshes while open.

* Toolbar badge spacing/width; Sheet: rename to #geohash and button 'teleport'.

- Move # label closer to peer count and widen to avoid truncation
- Change custom field placeholder to '#geohash' and action button to 'teleport' with monospaced font

* Sheet polish: style 'teleport' button with subtle background, disable until valid; prefix '#' label and placeholder 'geohash'; center + style 'remove location permission' and hide separators for these rows.  Toolbar: adjust spacing/width for # label.

* Sheet UX: restrict custom geohash input to valid base32 (lowercase, max 12), reduce spacing so placeholder sits closer to '#', add divider under country row, style 'remove permission' and hide row separators as before. Toolbar: minor spacing/width already adjusted.

* Sheet behavior: show channel list even without permission; add green 'get location and my geohash' button; ensure only one separator between country and teleport by removing manual Divider and showing default row separator; refine teleport input filtering and spacing.

* Channel activity nudges: notify after 9 minutes inactivity only in background; triple-tap clear also clears persistent timelines.

- ChatViewModel: track last activity per channel; send local notification when new activity resumes while app in background (with small cooldown)
- CommandProcessor: /clear clears current public channel persistence via viewModel helper

* Fix compile: add activeChannelDisplayName() and clearCurrentPublicTimeline() helpers in ChatViewModel.

* Fix concurrent dictionary access in BLEService.broadcastPacket: snapshot shared collections under collectionsQueue to avoid CocoaDictionary iterator crashes.

* People: channel-aware list and counts

- Sidebar: NETWORK → PEOPLE; removed PEOPLE subheader/icon
- Toolbar: blue #mesh badge; green #<geohash> badge; count color by channel
- Geohash participants: track per-geohash unique senders with 5m decay; publish list
- Update on geohash send/receive; 30s prune timer; channel switch hooks

No changes to mesh peer UX; mesh list retained as-is.

* BLE: snapshot collections for thread-safe access; stopServices uses snapshot; safe characteristic snapshot in broadcast path

LocationChannelsSheet: rename button label to 'remove location access'

* Channel sheet: show current peer counts

- Mesh row shows connected mesh peers count
- Geohash rows show 5m-active participant counts via ViewModel
- Live-updates while sheet is open

* Channel sheet: pluralize counts as 'person/people' in titles

* Geohash sampling: subscribe to all available channels while sheet open

- ViewModel: add multi-channel sampling subscriptions and per-geohash participant updates
- Sheet: start sampling on appear, sync on list changes, stop on disappear

* Channel sheet: render counts '(N person/people)' in smaller font next to label

* Channel sheet: use square brackets for counts and adjust parsing; fix mesh title to '#mesh'

* Geohash DMs: implement send/receive via NIP-17 with per-geohash identity

- NostrEmbeddedBitChat: add no-recipient encoder for geohash DMs
- NostrTransport: add sendPrivateMessageGeohash(using provided identity)
- ChatViewModel:
  • startGeohashDM + mapping helpers
  • subscribe to per-geohash gift wraps; store DMs in conversations keyed by 'nostr_<prefix>'
  • route sendPrivateMessage() for 'nostr_' to Nostr geohash send; local echo and status
  • map pubkeys from geohash public events for DM initiation
  • resubscribe DM feed on reconnect and channel switch; unsubscribe on leave
- ContentView: long-press 'private message' starts geohash DM when sender is nostr

* Geohash DMs UX: tap participants to DM; support /msg nickname in geohash; DM notifications

- People (geohash) list: bold 'you', sort to top, tap to open DM
- ChatViewModel.getPeerIDForNickname resolves geohash names to nostr_ conv keys
- Geohash DM receive: send local notification when not viewing

* Geohash DMs polish: header title, star hidden, self-DM blocked, message icon, delivered/read ACKs

- Header shows '#<geohash>/@name#abcd' for geohash DMs; hide favorite star
- Geohash people row: add small message icon; prevent self tap
- Prevent sending geohash DM to self
- Send delivery/read ACKs on receive; handle delivered/read to update status

* Geohash DMs: hide encryption status icon in DM header

* BLE: fix data race in broadcast path

- Snapshot peripherals via Array(values) and filter outside sync
- Snapshot subscribedCentrals and centralToPeerID under collectionsQueue
- Mutate subscribedCentrals under collectionsQueue barriers in didSubscribe/unsubscribe

* LocationChannelsSheet: open fully by default (large detent only)

* BLE: remove unused centralMapSnapshot variable

* Geohash DMs: only notify on incoming PM when app is backgrounded; avoid foreground noise

* GeoDM: reliable delivered/read receipts, background-only notifications, and UI tweak

- Implement delivered + read receipts for geohash DMs; send READ on open\n- Handle relay OK acks for gift-wrap sends; resubscribe processes PM/DELIVERED/READ\n- Prevent mesh Noise handshakes for virtual geohash peers (nostr_*)\n- Notify GeoDMs only in background; suppress alerts for already-read msgs\n- Logging: promote key GeoDM receive logs; demote/remove verbose noise\n- UI: remove trailing envelope button from geohash People list

* Fix: remove duplicate variable declarations in AnnouncementPacket.decode()

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-20 01:10:23 +02:00
1c33a92765 Feature/signed public identity (#456)
* Require signed announces; add Ed25519 key/signature/timestamp TLVs and verify

- Protocol: AnnouncementPacket now requires ed25519PublicKey (0x03), announceSignature (0x04), and announceTimestamp (0x05). Encoder emits, decoder requires; unknown TLVs still tolerated.
- NoiseEncryptionService: add canonical announce sign/verify helpers using context 'bitchat-announce-v1'.
- BLEService: sign Announce, include TLVs; on receive verify (±5 min skew) and ignore unverified; store ed25519 key and isVerifiedNickname in PeerInfo.
- Preserve 8-byte on-wire IDs to keep BLE headers small; no per-message bloat.

* Fix Data.append usage for timestamp bytes in Packets and NoiseEncryptionService (use append(contentsOf:) on UnsafeRawBufferPointer)

* BLEService: fix non-optional announce fields and unwrap signature result; enforce required verification path

* Enforce verified-only public messages; append peerID suffix on nickname collisions in handleMessage

* Suffix duplicate nicknames with peerID prefix in snapshots and getPeerNicknames; ensures lists and messages disambiguate 'jack' vs 'jack'

* Include self nickname in collision detection: suffix remote 'jack' when it matches our nickname in lists and public chat

* UI labels: remove space before '#abcd' suffix in names (public chat, peer lists, snapshots)

* Style '#abcd' suffix light gray:
- Public chat: color suffix in sender via AttributedString segments
- People list: split name and color suffix segment; add helper splitNameSuffix()

* Debounce 'bitchatters nearby' notification: add 60s grace before reset when mesh goes empty; cancel reset when peers return

* Lighten '#abcd' suffix: use Color.secondary.opacity(0.6) in public chat sender and People list

* Toolbar peers indicator: use blue when Bluetooth peers present (was default text color)

* Toolbar peers indicator: use grey when zero peers (was red)

* Toolbar peers indicator: use system grey (Color.secondary) when zero peers, not green

* Fix crash: mutate peripherals dict on BLE queue (not main). Move scan restart to BLE queue as well.

* Reduce connect timeout churn: back off peripherals that time out (15s), increase timeout to 8s, skip non-connectable adverts, and demote timeout log to debug; clean backoff map periodically

* Mentions: support '@name#abcd' disambiguation; filter hashtag/URL styling inside mentions; deliver notifications only to the specified suffixed target when collisions exist

* Fix string interpolation in mention log (escape sequence)

* Mentions: parse '@name#abcd' in sender/receiver; render mention suffix grey (not orange/blue/underlined); ensure receiver notifications trigger for suffixed tokens

* Mentions: include own suffixed token 'name#<myIDprefix>' in valid tokens so '@name#abcd' to self is recognized and notified

* Public actions: show own system message by processing own public messages (remove early-return). Private /hug: add local system message for sender's chat.

* Grammar: change local '/hug' message to past tense ('you hugged/slapped'). Notifications: only fire 'bitchatters nearby' on rising-edge; remove 5-min re-fire and increase empty reset grace to 10m.

* Public /hug echo: add local system message so sender sees action immediately (no reliance on echo)

* Fix visibility: expose addPublicSystemMessage on ChatViewModel and use it from CommandProcessor

* use noise pubkey wip

* ttl=0 for signatures

* verification works

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-19 23:37:15 +02:00
a30b73dd99 Feature/fragmentation fixes (#453)
* Fix fragmentation + BLE long-write + padding

- Accumulate CBATTRequest long writes by offset and decode once per central
- Decode original packet after fragment reassembly (preserve flags/compression)
- Switch MessagePadding to strict PKCS#7 and validate before unpadding
- Make BinaryProtocol.decode robust: try raw first, then unpad fallback
- Unpad frames before BLE notify; fragment when exceeding centrals' max update length
- Skip notify path when max update length < 21 bytes (protocol minimum)

Verified large PMs and announces route without decode errors and peers show reliably.

* Tests: fix weak delegate lifetime, legacy constants, and unused vars; fragment unpadded frames

- BLEServiceTests: hold strong reference to MockBitchatDelegate
- IntegrationTests: fix inline comment braces; replace removed types with test-safe values; use numeric 0x06 for legacy handshake resp checks
- BinaryProtocolTests: remove unused minResult variable
- BLEService: fragment the unpadded frame so fragments are efficient

* tests: add Noise rehandshake recovery test; document in-memory test bus and autoFlood; stabilize large-network broadcast

* tests: align suite with current behavior (compression, padding, routing, nonce); deflake and stabilize

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-19 01:22:21 +02:00
callebtcandGitHub 4c0bb5f93a LZ4 -> ZLIB (#452) 2025-08-18 19:49:39 +02:00
Mateusz MatoszkoandGitHub 7836daa6d3 Adds O(1) method for peer nickname retrieval (#450)
* Adds O(1) method for peerNickname retrieval

* Uses peerNickname method where possible
2025-08-17 21:29:15 +02:00
4f1ac30f12 Feat/mesh robustness efficiency (#451)
* chat: de-dup private chats across ephemeral/stable IDs; prefer most advanced delivery status\n\n- Fixes LazyVStack duplicate ID warnings and blank row in PM\n- Merges messages by id from ephemeral and Noise-key stores\n- Chooses read > delivered > partiallyDelivered > sent > sending > failed (newer wins on tie)\n- Ensures status icon updates immediately without waiting for another send\n- Adds exhaustive handling for DeliveryStatus in ranking

* logging: reduce noisy info logs to debug; keep errors/warnings\n\n- Downgrade routing/ACK/subscription/connect logs to debug\n- Retain security/fingerprint/keychain info logs\n- Keep errors and warnings intact\n\ndocs: add docs/privacy-assessment.md covering BLE privacy, routing TTL/jitter, Nostr E2E gift wraps, ACK throttling, and logging posture

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-17 21:25:25 +02:00
6fbf7eee25 Refactor/ble nostr boundaries (#449)
* Refactor: move Nostr embedding and TLVs out of BLE; add NostrEmbeddedBitChat, Packets, PeerIDUtils; centralize MessageDeduplicator; update ChatViewModel to use new helpers; remove AI_CONTEXT.md and CLAUDE.md

* Rename class to BLEService with compatibility alias; move mention parsing out of BLE; emit low-level BLE events to delegate; unify hex helpers; accept 64-hex in isPeerConnected; add PeerIDResolver

* Project: rename file to BLEService.swift and update Xcode project; keep typealias SimplifiedBluetoothService = BLEService for compatibility

* Remove SimplifiedBluetoothService alias; update app code to use BLEService explicitly

* Tests: rename MockSimplifiedBluetoothService to MockBLEService; update typealiases and Xcode project

* Docs: update comments to refer to BLEService (tests, protocol, noise service)

* Tests: rename SimplifiedBluetoothServiceTests to BLEServiceTests; update project references and class names

* Introduce Transport protocol; BLEService conforms; document delegate-only event pattern in BLEService; keep publishers internal for UnifiedPeerService

* Adopt Transport end-to-end: add TransportPeerSnapshot + publishers; BLEService maps to Transport snapshots; UnifiedPeerService consumes Transport; ChatViewModel holds Transport

* Fix Transport integration: replace getPeerFingerprint with getFingerprint(for:); update PrivateChatManager and CommandProcessor to use Transport; add BLEService.getFingerprint(for:); update PeerManager to use Transport

* Refactor transport and BLE/Nostr layers; unify UI events; fix MainActor isolation

- Rename SimplifiedBluetoothService to BLEService and slim responsibilities
- Introduce Transport protocol and peerEventsDelegate for UI updates
- Add NostrTransport and MessageRouter to route PM/read/favorite via BLE or Nostr
- Centralize TLVs, PeerID utils, and MessageDeduplicator outside BLE
- Update UnifiedPeerService and ChatViewModel to use Transport and delegate events
- Fix MainActor isolation: route delegate calls via Task on MainActor; update notifyUI helper
- Adjust related files and tests accordingly

* BLEService: remove internal publishers; switch to delegate-only events

- Drop legacy messages/peers/fullPeers publishers
- Provide lightweight peerSnapshotSubject only to satisfy Transport
- Rework publishFullPeerData to build snapshots from internal state and notify delegate + subject
- Remove all peersPublisher.send call sites
- Keep UnifiedPeerService on delegate updates exclusively

* Remove inlined Nostr send helpers from ChatViewModel; route via MessageRouter

- Replace direct Nostr sends (PM, ACKs, favorites) with MessageRouter
- Add router method for delivery ACKs and implement NostrTransport.sendDeliveryAck
- Simplify ChatViewModel favorite notification path to use router
- Keep Nostr receive handling intact; reduce duplication

* Fix ReadReceipt initializer usage in ChatViewModel (readerID + readerNickname)

* Fix unused variable warning: replace shadowed 'nostrPubkey' bind with boolean check in ChatViewModel

* Fix queued PM format: use TLV for pending messages after Noise handshake

- Pending messages (including first-time favorite notifications) now use the same TLV encoding as normal sends
- Ensures ChatViewModel can decode on first send, even if handshake completes after queuing

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-17 15:17:04 +02:00
3ebfa85e90 Feature/nostr embedded bitchat (#448)
* UI: prefer mesh radio icon when connected; map short peer ID to full Noise key; rename ephemeral mapping to shortIDToNoiseKey; ensure header flips to purple globe on disconnect and keeps name.

* chore: stop tracking build artifacts; ignore .DerivedData and .Result*

* logging: add global threshold via BITCHAT_LOG_LEVEL and demote chatty logs to debug; keep critical errors/warnings and key state transitions

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-17 11:25:42 +02:00
fb1988ac27 BLE privacy: derive peerID from Noise fingerprint; remove BLE Local Name from advertising; verify announces against key-derived ID; auto-initiate Noise handshake when encrypted message arrives without session; drop rotating alias option. (#447)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-17 02:20:49 +02:00
845ffc601b Refactor/robustness (#446)
* Refactor BitChat for improved robustness and performance

Major refactoring to simplify architecture and fix critical issues:

Architecture Improvements:
- Replace complex BluetoothMeshService with simplified SimplifiedBluetoothService
- Consolidate message routing and peer management into unified services
- Remove redundant caching layers and optimize performance

Bug Fixes:
- Fix critical BLE peer mapping corruption in mesh networks
- Fix encrypted message routing failures in multi-peer scenarios
- Fix app freezes and Main Thread Checker warnings
- Fix BLE message delivery in dual-role connections
- Fix favorite toggle UI not updating instantly
- Fix Nostr offline messaging with 24-hour message filtering

Features:
- Add command processor for chat commands
- Add autocomplete service for mentions and commands
- Improve private chat management with dedicated service
- Add unified peer service for consistent state management

Performance:
- Optimize BLE reconnection speed
- Reduce excessive logging throughout codebase
- Improve message deduplication efficiency
- Optimize UI updates and state management

* Improvements refactor robust (#441)

* remove unused code

* remove more

* TLV for announcement

* restore

* restore

* restore?

* messages tlv too (#442)

* Fix Nostr notification and read receipt issues, add TLV encoding, cleanup unused code

## Notification & Read Receipt Fixes
- Fixed toolbar notification icon appearing incorrectly on app restart for already-read messages
- Fixed read receipts being incorrectly deleted on startup when privateChats was empty
- Fixed messages not being marked as read when opening chat for first time
- Fixed senderPeerID not being updated during message consolidation
- Added startup phase logic to block old messages (>30s) while allowing recent ones
- Fixed unread status checking across all storage locations (ephemeral, stable Noise keys, temporary Nostr IDs)

## TLV Encoding Implementation
- Implemented Type-Length-Value encoding for private message payloads
- Added PrivateMessagePacket struct with TLV encode/decode methods
- Enhanced message structure for better extensibility and robustness

## Code Cleanup
- Removed unused PeerStateManager class and related dependencies
- Removed dead protocol types (DeliveryAck, ProtocolAck/Nack, NoiseIdentityAnnouncement)
- Cleaned up BitchatDelegate by removing unused methods
- Removed excessive debug logging throughout ChatViewModel
- Added test-only ProtocolNack helper for integration tests

## Technical Details
- Messages stored under three ID types: ephemeral peer IDs, stable Noise key hexes, temporary Nostr IDs
- Fixed cleanupOldReadReceipts() to skip when privateChats is empty or during startup
- Updated message consolidation to properly update senderPeerID
- Restored NIP-17 timestamp randomization (±15 minutes) for privacy

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
2025-08-17 01:51:54 +02:00
Mateusz MatoszkoandGitHub 47b0829685 Excludes Index.noindex in Justfile (#440) 2025-08-15 23:06:37 +02:00
Mario NachbaurandGitHub 030d6e0f11 Allow unicode letter characters in nicknames (#435) 2025-08-12 20:08:53 +02:00
db3c3b77f5 Remove dead store-and-forward and message aggregation code (#438)
- Remove completely unused message aggregation system (100% dead code)
- Remove broken store-and-forward implementation that only worked for relayed messages to offline favorites
- Update documentation to reflect actual functionality
- Net reduction of 312 lines of unmaintained code

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-12 20:08:37 +02:00
jack 26bcdf72d7 Merge remote-tracking branch 'origin/main' into code-cleanup 2025-08-12 11:43:52 +02:00
275f0ebaaf Remove dead code and simplify codebase (#436)
* refactor: remove dead code and consolidate system messages

- Delete 3 unused functions in ShareViewController (36 lines)
- Extract addSystemMessage() helper to eliminate duplication (120+ lines)
- Remove 22 'let _ =' wasteful computations across multiple files
- Net reduction of 215 lines of dead/duplicate code
- Improves maintainability and reduces technical debt

* fix: remove remaining unused variables to eliminate compiler warnings

- Remove unused senderNoiseKey in ChatViewModel
- Remove unused lastSuccess variable in BluetoothMeshService
- Eliminates all compiler warnings related to unused values

* refactor: remove all dead legacy and migration code

- Remove unused migrateSession() functions (never called in production)
  - NoiseSession.migrateSession() - 13 lines
  - NoiseEncryptionService.migratePeerSession() - 18 lines
  - Test for migration functionality - 17 lines

- Remove unnecessary keychain cleanup code (no legacy data existed)
  - cleanupLegacyKeychainItems() - 62 lines
  - aggressiveCleanupLegacyItems() - 72 lines
  - resetCleanupFlag() - 4 lines
  - Simplified panic mode to just use deleteAllKeychainData()

Total removed: 194 lines of dead/unnecessary code

Analysis revealed:
- KeychainManager introduced July 5, 2025
- Cleanup code added July 15, 2025 (10 days later)
- Legacy service names were never used in production
- Migration functions were incomplete implementation never called
- Peer ID rotation remains active (not legacy)

* Remove dead code and simplify codebase

- Remove unused BinaryEncodable protocol and BinaryMessageType enum
- Delete MockNoiseSession.swift (never used in tests)
- Remove all relay detection code (hardcoded to false)
  - Removed isRelayConnected property from BitchatPeer
  - Removed relayConnected case from ConnectionState enum
  - Cleaned up relay-related UI indicators in ContentView
  - Removed relay status checks from ChatViewModel
- Simplified peer connection logic by removing relay layer

Total: 169 lines removed across 5 files

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-12 11:33:08 +02:00
jack f4b8168ef9 Remove dead code and simplify codebase
- Remove unused BinaryEncodable protocol and BinaryMessageType enum
- Delete MockNoiseSession.swift (never used in tests)
- Remove all relay detection code (hardcoded to false)
  - Removed isRelayConnected property from BitchatPeer
  - Removed relayConnected case from ConnectionState enum
  - Cleaned up relay-related UI indicators in ContentView
  - Removed relay status checks from ChatViewModel
- Simplified peer connection logic by removing relay layer

Total: 169 lines removed across 5 files
2025-08-12 11:03:31 +02:00
jack 63f05b5d7e refactor: remove all dead legacy and migration code
- Remove unused migrateSession() functions (never called in production)
  - NoiseSession.migrateSession() - 13 lines
  - NoiseEncryptionService.migratePeerSession() - 18 lines
  - Test for migration functionality - 17 lines

- Remove unnecessary keychain cleanup code (no legacy data existed)
  - cleanupLegacyKeychainItems() - 62 lines
  - aggressiveCleanupLegacyItems() - 72 lines
  - resetCleanupFlag() - 4 lines
  - Simplified panic mode to just use deleteAllKeychainData()

Total removed: 194 lines of dead/unnecessary code

Analysis revealed:
- KeychainManager introduced July 5, 2025
- Cleanup code added July 15, 2025 (10 days later)
- Legacy service names were never used in production
- Migration functions were incomplete implementation never called
- Peer ID rotation remains active (not legacy)
2025-08-12 10:15:05 +02:00
jack a36eda3fbe fix: remove remaining unused variables to eliminate compiler warnings
- Remove unused senderNoiseKey in ChatViewModel
- Remove unused lastSuccess variable in BluetoothMeshService
- Eliminates all compiler warnings related to unused values
2025-08-12 09:43:06 +02:00
jack 99c0f6523e refactor: remove dead code and consolidate system messages
- Delete 3 unused functions in ShareViewController (36 lines)
- Extract addSystemMessage() helper to eliminate duplication (120+ lines)
- Remove 22 'let _ =' wasteful computations across multiple files
- Net reduction of 215 lines of dead/duplicate code
- Improves maintainability and reduces technical debt
2025-08-12 09:41:12 +02:00
7a7c89e689 Remove protocol versioning and handshake logic (#433)
Simplified the protocol by removing version negotiation and handshake sequences.
All devices now use protocol version 1 without negotiation. This eliminates
unnecessary connection overhead and complexity while maintaining full
compatibility across the network.

Changes:
- Removed versionHello and versionAck message types
- Simplified connection flow to use announce packets only
- Removed version negotiation state tracking
- Cleaned up handshake timeout logic
- Reduced connection establishment overhead

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-12 02:24:34 +02:00
3226b9cd14 Optimize logging to reduce verbosity while preserving critical network events (#432)
- Remove excessive verbose logging (DISCOVERY, INCOMING, PEER-UPDATE, etc.)
- Preserve critical network state logs (RESTORE, handshake failures, security events)
- Change routine key operations from info to debug level
- Add successful peer connection log after handshake completion
- Fix compiler warnings for unused variables
- Achieve ~95% reduction in log volume while maintaining debugging capability

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-11 23:45:59 +02:00
ChrisandGitHub 04c2b0caa6 fix: add secp256k1 dependency to resolve spm import error (#429) 2025-08-11 22:09:19 +02:00
callebtcandGitHub 29f1308e37 relay all packages (#431) 2025-08-11 22:05:25 +02:00
Alex RadandGitHub c6c186c77b Prevent spoofable plaintext messages from sliding into private chats (#428) 2025-08-11 17:05:36 +02:00
Mario NachbaurandGitHub d4262fab6c Remove noisy at symbol in mention (#420) 2025-08-08 18:41:50 +02:00
7876c8d96f Fix network flakiness and improve peer discovery (#405)
- Extend timeouts for better stability (availability: 30s->60s, cleanup: 3min->5min)
- Enable 30% relay probability for small networks to help discovery
- Add macOS-specific fixes for CoreBluetooth compatibility
- Implement rescan rate limiting to prevent battery drain
- Add comprehensive debug logging for network diagnostics
- Fix peripheral mapping and connection state management
- Improve relay-only session handling

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-05 10:13:41 +02:00
Steve LeeandGitHub 397c9f182b Clarify how packet loss is avoided with gossip protocol (#403)
Fixes an inaccurate description of Bloom filters and packet loss. Instead provides the actual reason to mitigate packet loss.
2025-08-04 22:32:15 +02:00
3ed37dfd0b Improve UI interactions (#390)
- Increase tap target size for back button in private message view
- Limit @mentions autocomplete to top 4 matches for better usability

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-02 11:48:19 +02:00
327fca9cb1 Remove cover traffic functionality (#389)
- Remove cover traffic variables and timer
- Remove cover traffic methods (startCoverTraffic, scheduleCoverTraffic, sendDummyMessage, generateDummyContent)
- Remove cover traffic initialization in startSession()
- Remove cover traffic check in handleReceivedPacket
- Remove timer invalidation in reset()
- Update README.md and AI_CONTEXT.md to remove cover traffic mentions

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-02 11:36:20 +02:00
871456896d Remove connection/disconnection system messages (#386)
- Remove system messages for peer connections to reduce chat noise
- Keep essential state management (ephemeral sessions, read receipts)
- Users can still see who's online via /w command

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-01 22:05:29 +02:00
b4b22e0e05 Add Bluetooth status alerts (#385)
- Add alert UI to notify users when Bluetooth is off/unauthorized
- Monitor Bluetooth state changes in BluetoothMeshService
- Show appropriate messages for different Bluetooth states
- Add Settings button to open system settings on iOS
- Check initial Bluetooth state on app startup

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-01 21:51:32 +02:00
jack 8ec39f566d Fix runtime crashes and reduce excessive logging
- Fix Dictionary crash in ChatViewModel by adding deduplication logic for peer IDs
- Fix compilation errors: PeerData -> BitchatPeer type correction
- Fix Task async context issue with cancellables
- Remove excessive debug logging for handshake coordination
- Remove repetitive keep-alive timer logs
- Remove version cache logging spam
2025-08-01 21:39:09 +02:00
jack 172b06721b Revert "Fix compilation errors in ChatViewModel"
This reverts commit e2d50e3684.
2025-08-01 20:26:28 +02:00
jack e2d50e3684 Fix compilation errors in ChatViewModel
- Fixed PeerData type reference (should be BitchatPeer)
- Fixed Task initialization in init() method with proper async/await syntax
- Fixed cancellables binding issue with proper unwrapping
- Maintained duplicate peer ID protection in peerIndex dictionary
2025-08-01 20:24:09 +02:00
jack d605a0b6db Fix crash from duplicate peer IDs in Dictionary initialization
- Added deduplication logic in ChatViewModel to handle duplicate peer IDs gracefully
- Enhanced PeerManager to prevent duplicate peers by tracking both nicknames and IDs
- Added final safety check to ensure no duplicates in peers array
- This fixes crash when Dictionary(uniqueKeysWithValues:) encounters duplicate keys
2025-08-01 19:04:36 +02:00
jack 1d698c2006 Fix @Unknown entries in autocomplete by improving nickname resolution
- Added getBestAvailableNickname() method to resolve nicknames from multiple sources
- Updated all PeerSession creations to use better nickname resolution
- Changed fallback from 'Unknown' to 'anon[peerID]' format for distinguishability
- Modified getPeerNicknames() to proactively update Unknown entries
- This ensures autocomplete shows meaningful nicknames instead of @Unknown
2025-08-01 19:01:07 +02:00
jack a92828471b Fix App Store submission: remove invalid background-processing from UIBackgroundModes 2025-08-01 16:58:13 +02:00
jack 69c8161cf8 Fix crash in BinaryProtocol.decode due to out-of-bounds data access
- Add comprehensive bounds checking before all data access operations
- Validate payload lengths don't exceed available data
- Protect against integer overflow in size calculations
- Handle malformed compressed packets gracefully
- Add extensive test coverage for edge cases

This fixes crashes when receiving malformed Bluetooth packets that claim
payload sizes larger than the actual data available.
2025-08-01 16:52:21 +02:00
aa1ecf40fc Fix iOS background Bluetooth connectivity issues (#378)
- Implement Core Bluetooth state restoration with restoration identifiers
- Add background task management to protect critical BLE operations
- Fix aggressive battery optimization that killed background connectivity
- Disable scan duty cycling in background (was causing 89-97% downtime)
- Add missing didEnterBackground/willEnterForeground notifications
- Fix advertising cutoff in low battery conditions (now only <10%)
- Add background-processing entitlement to Info.plist
- Optimize scan parameters for background vs foreground modes

These changes address the issue where devices lose mesh connectivity when
the app is backgrounded, ensuring continuous Bluetooth operation within
iOS background execution limits.

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-01 12:18:14 +02:00
b004bfa4aa Remove message batching system for simpler, faster UI updates (#377)
- Remove dual-timer batching architecture (100ms message timer, 50ms UI timer)
- Delete pending message queues and all batching infrastructure
- Simplify to direct message appends with duplicate detection
- Trust SwiftUI's built-in update optimization instead of manual batching
- Results in instant message display and 208 lines of code removed
- Eliminates timer management complexity and potential race conditions

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-01 11:38:53 +02:00
a6c2e751d2 Performance optimizations: LazyVStack, UI batching, timer consolidation (#375)
- Replace VStack with LazyVStack for message list to enable on-demand rendering
- Batch UI updates in ChatViewModel to reduce main thread operations
- Consolidate 12 timers into 3 (high/medium/low frequency) in BluetoothMeshService
- Fix thread safety in scheduleUIUpdate with main thread check

These changes significantly improve app responsiveness and reduce CPU usage.

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-08-01 01:05:59 +02:00
8f32edaa64 Security fixes and improvements (#374)
- Fix force unwrapping in NostrIdentity bech32 functions that could crash on non-ASCII input
- Add comprehensive input validation for all protocol messages (peer IDs, nicknames, timestamps)
- Strengthen keychain security with better sandbox detection and consistent app group usage
- Implement secure memory clearing for cryptographic keys and shared secrets
- Fix panic mode not reconnecting to mesh by restarting services after emergency disconnect

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-31 23:42:08 +02:00
Mateusz MatoszkoandGitHub 5a44b32719 Adds swift-secp256k1 to project.yml (#366) 2025-07-31 21:24:03 +02:00
jackandGitHub d85c9e226b Update README.md 2025-07-31 18:13:51 +02:00
jack f953c50565 Remove 'back' text from PM view, keep only chevron 2025-07-31 12:43:28 +02:00
2a081f65fc Group Connectivity Improvements (#365)
* Implement dynamic connection limits based on network size

Fixes connection thrashing in group scenarios by dynamically adjusting the connection limit based on the number of nearby peers.

Changes:
- Replace fixed maxConnectedPeripherals with dynamic calculation
- Maintain full mesh connectivity for small groups (<10 peers)
- Scale connection limit up to 2x for larger groups
- Override battery-based limits when needed to prevent thrashing
- Add logging to track dynamic limit changes

This solves the "perfect storm" issue where 6-8 people would constantly disconnect/reconnect when the power saver mode limited connections to 5.

* Implement optimistic version negotiation with caching

Skip version negotiation for known peers by caching negotiated versions for 24 hours.

Changes:
- Add version cache that persists beyond session lifetime
- Check cache before sending version hello
- Skip negotiation entirely for cached peers (instant connection)
- Cache cleanup runs every 60 seconds
- Invalidate cache on protocol errors for automatic fallback
- Log when using cached versions

This reduces protocol messages by ~40% for reconnecting peers and enables instant connections for known devices.

* Fix unused variable warning

* Implement protocol message deduplication

Suppress duplicate protocol messages within configurable time windows to reduce overhead.

Changes:
- Add deduplication tracker with per-message-type time windows
- Suppress duplicate announces within 5 seconds
- Suppress duplicate version negotiations within 10 seconds
- Track messages by peer ID and optional content hash
- Automatic cleanup of expired entries every 60 seconds
- Log when duplicates are suppressed

This reduces protocol message overhead by 20-30% in group scenarios where multiple connection attempts trigger redundant announcements and version negotiations.

* Fix MessageType enum case name

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-31 11:36:49 +02:00
jack 71b7f8edd3 Fix whitespace and project file updates 2025-07-31 11:34:51 +02:00
jack 46fd1d23d9 Remove duplicate libsecp256k1 import
P256K already includes libsecp256k1, so importing both was redundant and doubled the library size in the app bundle.
2025-07-31 10:53:43 +02:00
jack 6a9a1cdb3b Fix duplicate Nostr relay connections
Add check to prevent creating multiple WebSocket connections to the same relay when connect() is called multiple times during app startup.
2025-07-31 10:48:22 +02:00
VasilyKaiserandGitHub c74d6ad75e Update README.md (#360)
Add deepwiki link for developers who will consider contributing, to easily see how app is structured and other details.
2025-07-31 01:03:31 +02:00
jackandGitHub 439fb59fdd Update README.md 2025-07-31 01:00:13 +02:00
jackandGitHub 0a5e4b248f Update README.md 2025-07-31 00:58:57 +02:00
jack b6e6f0f63b Fix unused variable warnings in NostrProtocol.swift
Replace unused variable names with _ to silence compiler warnings:
- ephemeralPubkey calculation (line 40)
- senderPubkey calculation (line 216)
- timestamp formatter strings (lines 452-453, 456-457)
2025-07-30 23:22:02 +02:00
a97d5c2d5e Implement Nostr NIP-17 for offline messaging and performance optimizations (#358)
* Implement Nostr NIP-17 integration for offline mutual favorite messaging

- Add Nostr relay connectivity and NIP-17 gift-wrapped private messages
- Implement dual transport system: Bluetooth mesh + Nostr relays
- Add favorites persistence with mutual detection and Nostr key exchange
- Support offline messaging for mutual favorites via Nostr relays
- Handle peer identity rotation with automatic favorite key updates
- Fix UI to show all favorites (online and offline) in peer list
- Add proper message routing based on peer availability
- Update peer list icons: 📶 for mesh, 🌐 for Nostr, 🌙 for one-sided
- Fix toolbar display for offline peers in private chat view
- Add network entitlements for macOS and iOS
- Implement automatic noise key updates when peers reconnect

* Implement Nostr NIP-17 for private messaging between mutual favorites

- Add support for NIP-17 gift-wrapped private messages with double encryption
- Enable private messaging via Nostr when mutual favorites are offline
- Fix peer reconnection issues: users now stay in private chat when peer reconnects
- Fix read receipt delivery: send pending receipts when peer comes back online
- Add message ID tracking through Nostr transport for proper delivery acknowledgments
- Update peer noise key mapping when peers reconnect with different IDs
- Check for Nostr messages when app becomes active
- Implement 7-day message retrieval window for better reliability

* Fix private message UI refresh and adjust PEOPLE header spacing

- Fix UI not updating when receiving private messages on mesh
  - Add immediate batch processing for messages in active chat
  - Force UI update when viewing current chat peer
  - Ensure real-time message display without navigation
- Reduce PEOPLE header spacing from 16 to 12 points for tighter UI

* Fix build errors and unused value warnings in Nostr favorites integration

* Implement read receipts via Nostr

- Added sendReadReceipt method to MessageRouter to send receipts via mesh or Nostr
- Added handleReadReceipt to process incoming read receipts from Nostr
- Made ReadReceipt.readerID mutable to allow updates
- Added missing notification names and error cases
- Uncommented and enabled read receipt handling in ChatViewModel
- Read receipts now work seamlessly via both mesh and Nostr transports

* Fix ReadReceipt initialization - use correct constructor

* Implement persistent message deduplication for Nostr

- Added ProcessedMessagesService to track messages across app restarts
- Store processed message IDs and last timestamp in UserDefaults
- Skip already processed messages when receiving from Nostr
- Adjust subscription filter to use smart timestamp (last processed or 24h)
- Prevents duplicate messages when reconnecting to Nostr relays

* Fix peer list UI not updating to Nostr mode on disconnect

- Remove peer from peerNicknames when connection state changes to disconnected
- Ensures UI properly reflects peer disconnection state
- Peer list now correctly shows Nostr mode (🌐) when peer walks out of range

* Update peer count to include Nostr peers and improve UI indicators

- Peer count now shows total peers including those available via Nostr
- Count appears purple when only Nostr peers are connected
- Private message header shows purple globe icon for Nostr transport
- Consistent visual language for Nostr connectivity across the app

* Improve RSSI real-time updates and fix UI flashing

- Reduce RSSI update timer from 10s to 5s and per-peripheral from 5s to 3s
- Add RSSI change detection with 2 dBm threshold for responsive updates
- Always update previous RSSI values to fix gradual change detection bug
- Trigger RSSI read on peer authentication for immediate status
- Fix UI flashing 'nobody around' by removing array clearing on updates
- Add proper cleanup of RSSI tracking on disconnect and peer rotation

* Fix favorite nickname updates and peer list filtering

- Add updateNickname method to FavoritesPersistenceService to update nicknames while preserving favorite status
- Update announce handler to check for existing favorites and update their nicknames
- Remove dead BluetoothMeshService+PublicAPI.swift file
- Move sendFavoriteNotification to main BluetoothMeshService
- Fix peer list to only show connected peers and user's favorites (not peers who favorite the user)
- Remove UI logic for showing peers who favorite us but we don't favorite back

* Remove dead code and fix ghost connections

Phase 1 - Remove abandoned peer ID rotation code:
- Remove previousPeerID property and rotationGracePeriod constant
- Remove grace period logic from isPeerIDOurs()
- Remove previousPeerID handling from announce packets
- Pass nil for previousPeerID in identity announcements

Phase 2 - Fix ghost connections from relayed packets:
- CRITICAL FIX: Only add peers to activePeers if they have a peripheral connection
- Check for peripheral connection before marking peer as active
- Prevents ghost connections when announce packets are relayed
- Log warning when rejecting relayed announce without peripheral

Phase 3 - Begin consolidating redundant peer tracking:
- Create new PeerSession class to unify peer data in one place
- Add helper methods for PeerSession management
- Integrate PeerSession into announce packet handling
- Update authentication state changes to use PeerSession
- Update peripheral mapping and RSSI to sync with PeerSession
- Update disconnect and leave handling to update PeerSession
- Add consolidated getter methods for peer info

This fixes the issue where peers appeared connected without actually having a Bluetooth connection, and begins the migration to a cleaner single-source-of-truth peer tracking system.

* Fix multiple connect messages on peer restart

- Move hasPeripheralConnection check outside sync block to fix scope issue
- Add debug logging to track connect message conditions
- Ensure connect messages only show on first connection or reconnection with peripheral

* Optimize RSSI updates for better battery life

- Add app state tracking to BluetoothMeshService
- Only update RSSI when app is in foreground and peer list is visible
- Add setPeerListVisible method to control RSSI updates
- Remove individual periodic RSSI updates in favor of centralized timer
- Update ContentView to notify mesh service of peer list visibility changes
- Improve battery efficiency by avoiding unnecessary RSSI reads

* Initialize peer list visibility state on view appear

- Ensure RSSI timer state is properly initialized when view loads
- Call setPeerListVisible with initial showSidebar value

* Fix duplicate peers and multiple disconnect messages

- Fixed duplicate peer entries when relay-connected by adding relay-connected peers to connectedNicknames set
- Added deduplication logic for disconnect messages with 2-second window to prevent multiple disconnect notifications for same peer
- Added cleanup for old disconnect notification tracking to prevent memory growth

* Fix peer count indicator color logic

- Show green for any mesh peer (direct Bluetooth or relay connected)
- Show purple only for Nostr-only peers (no mesh connections)
- Show red only when no peers are reachable at all
- Fixed to use meshPeerCount instead of viewModel.isConnected which only checked direct connections

* Fix relay connection issues and peripheral mapping cleanup

- Fixed relay-connected peers being marked as directly connected when receiving identity announce
- Added proper cleanup of temp peripheral mappings when discovering real peer ID
- Fixed disconnect notification deduplication cleanup
- Improved debug logging to show actual connection state (direct/relay/nostr/offline)
- Added debug logging for relay connection detection
- Fixed compiler warning about unused variable

* Fix Unknown peer disconnect notifications and disable faulty relay detection

- Add check to prevent disconnect notifications for Unknown peers that never announced
- Disable relay connection detection until proper relay tracking is implemented
- In a 2-peer network, peers should never show as relay-connected

* Fix RSSI updates and peer visibility after reconnection

- Add updatePeers() call in didUpdatePeerList to refresh RSSI values in UI
- Track version hello times to better detect direct connections
- Allow peers to be marked active if recent version hello received
- Fix thread safety for version hello tracking
- Clean up old version hello times to prevent memory leaks

* Remove RSSI tracking completely and replace with radio icon for mesh connections

* Fix build errors after RSSI removal

- Add missing peripheralID declaration in didDiscover delegate method
- Remove obsolete setPeerListVisible calls from ContentView

* Center private message header elements using ZStack layout

- Replace HStack with ZStack for perfect centering
- Globe/nick/lock cluster now always centered regardless of button sizes
- Back and favorite buttons positioned in overlay HStack

* Fix private chat view showing Unknown when peer reconnects with new ID

- Update FavoritesPersistenceService to notify with both old and new keys
- Handle peer ID changes in ChatViewModel to migrate private chat data
- Update selectedPrivateChatPeer when favorite's noise key changes
- Maintain chat history and unread status across peer ID changes

* Fix read receipts after peer reconnection and replace nos.lol relay

- Updated sendReadReceipt to resolve current peer ID when peers reconnect with new IDs
- Enhanced MessageRouter to check favorites for current noise keys
- Replaced nos.lol relay with relay.snort.social to avoid PoW requirements

* Fix message routing to use Nostr when peers are disconnected

Changed message routing logic to check actual peer connection status using
isPeerConnected() instead of just checking if peer exists in nickname list.
This ensures that offline mutual favorites correctly route messages through
Nostr instead of attempting Bluetooth handshakes.

Also added safety check to prevent starting private chat with ourselves.

* Add debug logging for Nostr timestamp randomization

Added logging to track the random offset being applied to Nostr event
timestamps to debug why messages appear 8-9 minutes in the future.

* Fix Nostr timestamp issue by reducing randomization range

Temporarily reduced the timestamp randomization from +/-15 minutes to +/-1 minute
to address messages appearing 8-9 minutes in the future. Added detailed UTC/local
time logging to help debug the issue.

The random offset should have been evenly distributed but was consistently
showing positive offsets. This change mitigates the issue while we investigate
the root cause.

* Fix message routing for offline favorites and reduce Nostr timestamp randomization

- Fix transport selection to properly detect disconnected peers using isPeerConnected()
- Change from checking peer nicknames to checking actual connection status
- Reduce Nostr timestamp randomization from ±15 minutes to ±1 minute
- Add detailed timestamp logging for debugging

* Improve PM header UI and encryption status display

- Show transport icons (radio/link/globe) in PM header matching peer list
- Always show lock icon if noise session ever established (no handshake icon)
- Change verified icon from shield to checkmark seal
- Use consistent green color (textColor) for PM header and encryption icons

* Update AI_CONTEXT.md with comprehensive Nostr implementation details

- Add Nostr and MessageRouter to architecture diagram
- Document NIP-17 gift wrap implementation
- Explain favorites integration and mutual requirement
- Detail message routing logic and transport selection
- Add security considerations and debugging tips
- Update common tasks with Nostr-specific guidance

* Fix data consistency issues in favorites, chat migration, and bloom filter

- Fix favorites deduplication to use public key instead of nickname
  Prevents losing favorites when multiple peers use same nickname

- Fix private chat migration to use fingerprints instead of nicknames
  Prevents merging unrelated conversations that share nicknames
  Fallback to nickname matching only for legacy data without fingerprints

- Fix bloom filter reset to preserve messages from last 10 minutes
  Prevents duplicate message processing after bloom filter resets
  Keeps processedMessages for 10 minutes while bloom filter resets every 5

* Add mutual favorites internet messaging to app info

* Remove excessive debug/info logging for production readiness

- Removed ~140 debug/info level logs across core services
- Preserved critical logs: errors, warnings, security events, state changes
- Kept logs for: peer join/leave, favorite status, mutual relationships
- Cleaned up verbose logging in: Bluetooth mesh, Nostr, message routing
- Improved performance by reducing log I/O overhead

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Implement performance optimizations and fix build warnings

- Add UI update debouncing (50ms) to prevent excessive SwiftUI refreshes
- Implement memory bounds for processedMessages with LRU eviction
- Add encryption queue cleanup for disconnected peers
- Optimize peer lookups from O(n) to O(1) with indexed dictionary
- Fix multiple compiler warnings (unused variables, missing break statements)
- Optimize peer counting with single-pass reduce operation
- Fix ViewBuilder control flow issue in ContentView
- Fix Dictionary initialization type mismatches with Array wrapper

* Add TTL-based cleanup for Noise handshake sessions

- Add session TTL (5 minutes) and max session limit (50) to NoiseHandshakeCoordinator
- Clean up old established sessions to prevent unbounded memory growth
- Move handshake cleanup timer out of DEBUG conditional for production use
- Run cleanup every 60 seconds in production (vs 30s in debug)
- Clean up crypto state immediately on peer disconnect
- Prevents memory leaks from accumulating Noise sessions

* Pre-compute and store fingerprints in PeerSession for O(1) lookups

- Store fingerprint in PeerSession when peer authenticates
- Update getPeerFingerprint() and getFingerprint() to check PeerSession first
- Replace all noiseService.getPeerFingerprint() calls with optimized version
- Eliminates repeated SHA256 calculations during message processing
- Improves performance for favorite checks and encryption status updates

* Implement exponential backoff for Nostr relay connections

- Add reconnection tracking fields to Relay struct (attempts, timing)
- Replace fixed 5-second delay with exponential backoff (1s → 2s → 4s... max 5min)
- Stop reconnection attempts after 10 failures to prevent infinite retries
- Reset attempt counter on successful connection
- Add utility methods: retryConnection(), getRelayStatuses(), resetAllConnections()
- DNS failures still bypass retry logic as before
- Improves battery life and reduces server load from constant reconnection attempts

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-30 23:14:17 +02:00
Tim JohnsenandGitHub a438c46817 Disable sharing images via extension, not supported at the moment. (#346) 2025-07-29 17:48:50 +02:00
jackandGitHub 41810ad419 Update README.md 2025-07-28 16:49:46 +02:00
jackandGitHub 54fbee786c Update README.md 2025-07-28 16:49:25 +02:00
jackandGitHub e6a5ca4023 Update README.md 2025-07-28 16:48:00 +02:00
jack fe8cb41ff7 Update Xcode project file 2025-07-28 12:18:14 +02:00
4867ddca0d Add comprehensive AI-friendly documentation across core files (#328)
- Created AI_CONTEXT.md as central documentation hub for AI assistants
- Added detailed file-level documentation to all major components
- Documented architecture, design decisions, and security considerations
- Added usage examples and integration guidance
- Improved code discoverability with clear component descriptions

Documentation covers:
- BluetoothMeshService: Core networking and mesh protocol
- BitchatProtocol: Application-layer protocol design
- NoiseProtocol: Cryptographic implementation details
- ChatViewModel: Business logic and state management
- IdentityModels: Three-layer identity architecture
- NoiseEncryptionService: High-level encryption API
- SecureIdentityStateManager: Secure persistence layer
- BinaryProtocol: Low-level wire format

This documentation will significantly improve AI understanding of the codebase structure and enable faster, more accurate assistance with development tasks.

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-27 10:18:47 +02:00
e282d077a3 fix iOS app zoom/compat mode issue (issue #236) (#327)
Co-authored-by: kevin <kevin@none>
2025-07-27 08:01:59 +02:00
jackandGitHub 34b2b1eee0 Update README.md 2025-07-26 11:54:39 +02:00
54c7eba8cb Improve code organization and documentation (#325)
* Add MARK headers to improve code organization in major files

* Reorganize peer management functions in BluetoothMeshService

- Removed duplicate getCurrentPeerID(for:) function
- Consolidated peer identity functions in Peer Identity Mapping section
- Moved getPeerFingerprint(), getFingerprint(for:), isPeerIDOurs() to proper location
- Moved getCurrentPeerIDForFingerprint() and getCurrentPeerIDs() from Message Sending section
- Moved notifyPeerIDChange() to Peer Management section

* Consolidate peer management functions in BluetoothMeshService

- Moved getCachedPublicKey() and getCachedSigningKey() from Identity Cache Methods to Peer Connection Management
- Moved getPeerNicknames() and getPeerRSSI() to Peer Connection Management section
- Moved getAllConnectedPeerIDs(), notifyPeerListUpdate(), and cleanupStalePeers() to Peer Connection Management
- Removed duplicate function declarations after consolidation
- Improved code organization by grouping all peer-related functions together

* Consolidate message handling functions in ChatViewModel

- Moved handleHandshakeRequest() from floating location to Message Reception section
- Moved trimMessagesIfNeeded() and trimPrivateChatMessagesIfNeeded() to Message Batching section
- Improved code organization by grouping related message handling functions together
- Removed unnecessary comments from trim functions

* Improve ContentView organization with better documentation

- Added descriptive comments for complex inline computations
- Documented message extraction logic for private vs public chats
- Documented peer data computation and sorting logic
- Improved code readability by explaining complex operations inline
- Note: Attempted to extract complex computations into helper functions, but SwiftUI scope limitations made inline documentation a better approach

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2025-07-26 00:11:23 +02:00
jackandGitHub 4568951736 Update WHITEPAPER.md 2025-07-25 20:57:19 +02:00
jack 0e78341102 Trim whitespace from nicknames to prevent display issues
- Added didSet observer to nickname property to trim on every change
- Trim nickname when loading from UserDefaults
- Update validateAndSaveNickname to properly trim
- Trim received nicknames in announce packets
- Add custom init/decoder for NoiseIdentityAnnouncement to ensure trimming
- Trim nicknames when decoding from binary data
2025-07-25 20:29:50 +02:00
1604 changed files with 257098 additions and 12851 deletions
+40
View File
@@ -0,0 +1,40 @@
name: Fetch GeoRelays Data
on:
schedule:
- cron: '0 6 * * 0'
workflow_dispatch:
permissions:
contents: write
jobs:
update-relay-data:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Fetch GeoRelays
run: |
wget https://raw.githubusercontent.com/permissionlesstech/georelays/refs/heads/main/nostr_relays.csv
mv nostr_relays.csv ./relays/online_relays_gps.csv
- name: Check for changes
id: git-check
run: |
git diff --exit-code || echo "changes=true" >> $GITHUB_OUTPUT
- name: Commit and push changes
if: steps.git-check.outputs.changes == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add relays/online_relays_gps.csv
git commit -m "Automated update of relay data - $(date -u)"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+13
View File
@@ -5,6 +5,10 @@
## implementation plans ## implementation plans
plans/ plans/
## AI
CLAUDE.md
AGENTS.md
## User settings ## User settings
xcuserdata/ xcuserdata/
@@ -15,6 +19,7 @@ xcuserdata/
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/ build/
DerivedData/ DerivedData/
.DerivedData/
*.moved-aside *.moved-aside
*.pbxuser *.pbxuser
!default.pbxuser !default.pbxuser
@@ -62,3 +67,11 @@ __pycache__/
## Temporary files ## Temporary files
*.tmp *.tmp
*.temp *.temp
# Local build results
.Result*/
.Result*.xcresult/
TestResult.xcresult/
*.xcresult/
build.log
*.log
+3 -3
View File
@@ -37,7 +37,7 @@ This three-message pattern provides:
#### NoiseEncryptionService #### NoiseEncryptionService
The main service managing all Noise operations: The main service managing all Noise operations:
```swift ```swift
class NoiseEncryptionService { final class NoiseEncryptionService {
private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey
private let sessionManager: NoiseSessionManager private let sessionManager: NoiseSessionManager
private let channelEncryption = NoiseChannelEncryption() private let channelEncryption = NoiseChannelEncryption()
@@ -47,7 +47,7 @@ class NoiseEncryptionService {
#### NoiseSession #### NoiseSession
Individual session state for each peer: Individual session state for each peer:
```swift ```swift
class NoiseSession { final class NoiseSession {
private var handshakeState: NoiseHandshakeState? private var handshakeState: NoiseHandshakeState?
private var sendCipher: NoiseCipherState? private var sendCipher: NoiseCipherState?
private var receiveCipher: NoiseCipherState? private var receiveCipher: NoiseCipherState?
@@ -58,7 +58,7 @@ class NoiseSession {
#### NoiseSessionManager #### NoiseSessionManager
Thread-safe session management: Thread-safe session management:
```swift ```swift
class NoiseSessionManager { final class NoiseSessionManager {
private var sessions: [String: NoiseSession] = [:] private var sessions: [String: NoiseSession] = [:]
private let sessionsQueue = DispatchQueue(label: "noise.sessions", attributes: .concurrent) private let sessionsQueue = DispatchQueue(label: "noise.sessions", attributes: .concurrent)
} }
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AvailableLibraries</key>
<array>
<dict>
<key>BinaryPath</key>
<string>tor-nolzma.framework/tor-nolzma</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>tor-nolzma.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>tor-nolzma.framework/tor-nolzma</string>
<key>LibraryIdentifier</key>
<string>macos-arm64</string>
<key>LibraryPath</key>
<string>tor-nolzma.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>macos</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>
@@ -0,0 +1,324 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file config.h
* \brief Header file for config.c.
**/
#ifndef TOR_CONFIG_H
#define TOR_CONFIG_H
#include "app/config/or_options_st.h"
#include "lib/testsupport/testsupport.h"
#include "app/config/quiet_level.h"
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(DARWIN)
#define KERNEL_MAY_SUPPORT_IPFW
#endif
/** Lowest allowable value for HeartbeatPeriod; if this is too low, we might
* expose more information than we're comfortable with. */
#define MIN_HEARTBEAT_PERIOD (30*60)
/** Maximum default value for MaxMemInQueues, in bytes. */
#if SIZEOF_VOID_P >= 8
#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (UINT64_C(8) << 30)
#else
#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (UINT64_C(2) << 30)
#endif
MOCK_DECL(const or_options_t *, get_options, (void));
MOCK_DECL(or_options_t *, get_options_mutable, (void));
int set_options(or_options_t *new_val, char **msg);
void config_free_all(void);
const char *safe_str_client(const char *address);
const char *safe_str(const char *address);
const char *escaped_safe_str_client(const char *address);
const char *escaped_safe_str(const char *address);
void init_protocol_warning_severity_level(void);
int get_protocol_warning_severity_level(void);
#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
/** Pattern for backing up configuration files */
#define CONFIG_BACKUP_PATTERN "%s.orig.1"
/** An error from options_trial_assign() or options_init_from_string(). */
typedef enum setopt_err_t {
SETOPT_OK = 0,
SETOPT_ERR_MISC = -1,
SETOPT_ERR_PARSE = -2,
SETOPT_ERR_TRANSITION = -3,
SETOPT_ERR_SETTING = -4,
} setopt_err_t;
setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags,
char **msg);
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
#define OPTIONS_DUMP_ALL 2
char *options_dump(const or_options_t *options, int how_to_dump);
int options_init_from_torrc(int argc, char **argv);
setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf,
int command, const char *command_arg, char **msg);
int option_is_recognized(const char *key);
const char *option_get_canonical_name(const char *key);
struct config_line_t *option_get_assignment(const or_options_t *options,
const char *key);
int options_save_current(void);
const char *get_torrc_fname(int defaults_fname);
typedef enum {
DIRROOT_DATADIR,
DIRROOT_CACHEDIR,
DIRROOT_KEYDIR
} directory_root_t;
MOCK_DECL(char *,
options_get_dir_fname2_suffix,
(const or_options_t *options,
directory_root_t roottype,
const char *sub1, const char *sub2,
const char *suffix));
/* These macros wrap options_get_dir_fname2_suffix to provide a more
* convenient API for finding filenames that Tor uses inside its storage
* They are named according to a pattern:
* (options_)?get_(cache|key|data)dir_fname(2)?(_suffix)?
*
* Macros that begin with options_ take an options argument; the others
* work with respect to the global options.
*
* Each macro works relative to the data directory, the key directory,
* or the cache directory, as determined by which one is mentioned.
*
* Macro variants with "2" in their name take two path components; others
* take one.
*
* Macro variants with "_suffix" at the end take an additional suffix
* that gets appended to the end of the file
*/
#define options_get_datadir_fname2_suffix(options, sub1, sub2, suffix) \
options_get_dir_fname2_suffix((options), DIRROOT_DATADIR, \
(sub1), (sub2), (suffix))
#define options_get_cachedir_fname2_suffix(options, sub1, sub2, suffix) \
options_get_dir_fname2_suffix((options), DIRROOT_CACHEDIR, \
(sub1), (sub2), (suffix))
#define options_get_keydir_fname2_suffix(options, sub1, sub2, suffix) \
options_get_dir_fname2_suffix((options), DIRROOT_KEYDIR, \
(sub1), (sub2), (suffix))
#define options_get_datadir_fname(opts,sub1) \
options_get_datadir_fname2_suffix((opts),(sub1), NULL, NULL)
#define options_get_datadir_fname2(opts,sub1,sub2) \
options_get_datadir_fname2_suffix((opts),(sub1), (sub2), NULL)
#define get_datadir_fname2_suffix(sub1, sub2, suffix) \
options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix))
#define get_datadir_fname(sub1) \
get_datadir_fname2_suffix((sub1), NULL, NULL)
#define get_datadir_fname2(sub1,sub2) \
get_datadir_fname2_suffix((sub1), (sub2), NULL)
#define get_datadir_fname_suffix(sub1, suffix) \
get_datadir_fname2_suffix((sub1), NULL, (suffix))
/** DOCDOC */
#define options_get_keydir_fname(options, sub1) \
options_get_keydir_fname2_suffix((options), (sub1), NULL, NULL)
#define get_keydir_fname_suffix(sub1, suffix) \
options_get_keydir_fname2_suffix(get_options(), (sub1), NULL, suffix)
#define get_keydir_fname(sub1) \
options_get_keydir_fname2_suffix(get_options(), (sub1), NULL, NULL)
#define get_cachedir_fname(sub1) \
options_get_cachedir_fname2_suffix(get_options(), (sub1), NULL, NULL)
#define get_cachedir_fname_suffix(sub1, suffix) \
options_get_cachedir_fname2_suffix(get_options(), (sub1), NULL, (suffix))
#define safe_str_client(address) \
safe_str_client_opts(NULL, address)
#define safe_str(address) \
safe_str_opts(NULL, address)
const char * safe_str_client_opts(const or_options_t *options,
const char *address);
const char * safe_str_opts(const or_options_t *options,
const char *address);
int using_default_dir_authorities(const or_options_t *options);
int create_keys_directory(const or_options_t *options);
int check_or_create_data_subdir(const char *subdir);
int write_to_data_subdir(const char* subdir, const char* fname,
const char* str, const char* descr);
int get_num_cpus(const or_options_t *options);
MOCK_DECL(const smartlist_t *,get_configured_ports,(void));
int port_binds_ipv4(const port_cfg_t *port);
int port_binds_ipv6(const port_cfg_t *port);
int portconf_get_first_advertised_port(int listener_type,
int address_family);
#define portconf_get_primary_dir_port() \
(portconf_get_first_advertised_port(CONN_TYPE_DIR_LISTENER, AF_INET))
const tor_addr_t *portconf_get_first_advertised_addr(int listener_type,
int address_family);
int port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr,
int port, int check_wildcard);
int port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h,
int port, int check_wildcard);
char *get_first_listener_addrport_string(int listener_type);
int options_need_geoip_info(const or_options_t *options,
const char **reason_out);
int getinfo_helper_config(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
int init_cookie_authentication(const char *fname, const char *header,
int cookie_len, int group_readable,
uint8_t **cookie_out, int *cookie_is_set_out);
or_options_t *options_new(void);
/** Options settings parsed from the command-line. */
typedef struct {
/** List of options that can only be set from the command-line */
struct config_line_t *cmdline_opts;
/** List of other options, to be handled by the general Tor configuration
system. */
struct config_line_t *other_opts;
/** Subcommand that Tor has been told to run */
tor_cmdline_mode_t command;
/** Argument for the command mode, if any. */
const char *command_arg;
/** How quiet have we been told to be? */
quiet_level_t quiet_level;
} parsed_cmdline_t;
parsed_cmdline_t *config_parse_commandline(int argc, char **argv,
int ignore_errors);
void parsed_cmdline_free_(parsed_cmdline_t *cmdline);
#define parsed_cmdline_free(c) \
FREE_AND_NULL(parsed_cmdline_t, parsed_cmdline_free_, (c))
void config_register_addressmaps(const or_options_t *options);
/* XXXX move to connection_edge.h */
int addressmap_register_auto(const char *from, const char *to,
time_t expires,
addressmap_entry_source_t addrmap_source,
const char **msg);
int port_cfg_line_extract_addrport(const char *line,
char **addrport_out,
int *is_unix_out,
const char **rest_out);
/** Represents the information stored in a torrc Bridge line. */
typedef struct bridge_line_t {
tor_addr_t addr; /* The IP address of the bridge. */
uint16_t port; /* The TCP port of the bridge. */
char *transport_name; /* The name of the pluggable transport that
should be used to connect to the bridge. */
char digest[DIGEST_LEN]; /* The bridge's identity key digest. */
smartlist_t *socks_args; /* SOCKS arguments for the pluggable
transport proxy. */
} bridge_line_t;
void bridge_line_free_(bridge_line_t *bridge_line);
#define bridge_line_free(line) \
FREE_AND_NULL(bridge_line_t, bridge_line_free_, (line))
bridge_line_t *parse_bridge_line(const char *line);
/* Port helper functions. */
int options_any_client_port_set(const or_options_t *options);
int port_parse_config(smartlist_t *out,
const struct config_line_t *ports,
const char *portname,
int listener_type,
const char *defaultaddr,
int defaultport,
const unsigned flags);
#define CL_PORT_NO_STREAM_OPTIONS (1u<<0)
#define CL_PORT_WARN_NONLOCAL (1u<<1)
/* Was CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2) */
#define CL_PORT_SERVER_OPTIONS (1u<<3)
#define CL_PORT_FORBID_NONLOCAL (1u<<4)
#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
#define CL_PORT_IS_UNIXSOCKET (1u<<6)
#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)
port_cfg_t *port_cfg_new(size_t namelen);
#define port_cfg_free(port) \
FREE_AND_NULL(port_cfg_t, port_cfg_free_, (port))
void port_cfg_free_(port_cfg_t *port);
int port_count_real_listeners(const smartlist_t *ports,
int listenertype,
int count_sockets);
int pt_parse_transport_line(const or_options_t *options,
const char *line, int validate_only,
int server);
int config_ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg);
#ifdef CONFIG_PRIVATE
MOCK_DECL(STATIC int, options_act,(const or_options_t *old_options));
MOCK_DECL(STATIC int, options_act_reversible,(const or_options_t *old_options,
char **msg));
struct config_mgr_t;
STATIC const struct config_mgr_t *get_options_mgr(void);
#define or_options_free(opt) \
FREE_AND_NULL(or_options_t, or_options_free_, (opt))
STATIC void or_options_free_(or_options_t *options);
STATIC int options_validate_single_onion(or_options_t *options,
char **msg);
STATIC int parse_tcp_proxy_line(const char *line, or_options_t *options,
char **msg);
STATIC int consider_adding_dir_servers(const or_options_t *options,
const or_options_t *old_options);
STATIC void add_default_trusted_dir_authorities(dirinfo_type_t type);
MOCK_DECL(STATIC void, add_default_fallback_dir_servers, (void));
STATIC int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
STATIC int parse_dir_fallback_line(const char *line, int validate_only);
STATIC uint64_t compute_real_max_mem_in_queues(const uint64_t val,
bool is_server);
STATIC int open_and_add_file_log(const log_severity_list_t *severity,
const char *fname,
int truncate_log);
STATIC int options_init_logs(const or_options_t *old_options,
const or_options_t *options, int validate_only);
STATIC int options_create_directories(char **msg_out);
struct log_transaction_t;
STATIC struct log_transaction_t *options_start_log_transaction(
const or_options_t *old_options,
char **msg_out);
STATIC void options_commit_log_transaction(struct log_transaction_t *xn);
STATIC void options_rollback_log_transaction(struct log_transaction_t *xn);
#ifdef TOR_UNIT_TESTS
int options_validate(const or_options_t *old_options,
or_options_t *options,
char **msg);
#endif
STATIC int parse_ports(or_options_t *options, int validate_only,
char **msg, int *n_ports_out,
int *world_writable_control_socket);
#endif /* defined(CONFIG_PRIVATE) */
#endif /* !defined(TOR_CONFIG_H) */
@@ -0,0 +1,103 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file or_state_st.h
*
* \brief The or_state_t structure, which represents Tor's state file.
*/
#ifndef TOR_OR_STATE_ST_H
#define TOR_OR_STATE_ST_H
#include "lib/cc/torint.h"
struct smartlist_t;
struct config_suite_t;
/** Persistent state for an onion router, as saved to disk. */
struct or_state_t {
uint32_t magic_;
/** The time at which we next plan to write the state to the disk. Equal to
* TIME_MAX if there are no saveable changes, 0 if there are changes that
* should be saved right away. */
time_t next_write;
/** When was the state last written to disk? */
time_t LastWritten;
/** Fields for accounting bandwidth use. */
time_t AccountingIntervalStart;
uint64_t AccountingBytesReadInInterval;
uint64_t AccountingBytesWrittenInInterval;
int AccountingSecondsActive;
int AccountingSecondsToReachSoftLimit;
time_t AccountingSoftLimitHitAt;
uint64_t AccountingBytesAtSoftLimit;
uint64_t AccountingExpectedUsage;
/** A list of guard-related configuration lines. */
struct config_line_t *Guard;
struct config_line_t *TransportProxies;
/** These fields hold information on the history of bandwidth usage for
* servers. The "Ends" fields hold the time when we last updated the
* bandwidth usage. The "Interval" fields hold the granularity, in seconds,
* of the entries of Values. The "Values" lists hold decimal string
* representations of the number of bytes read or written in each
* interval. The "Maxima" list holds decimal strings describing the highest
* rate achieved during the interval.
*/
time_t BWHistoryReadEnds;
int BWHistoryReadInterval;
struct smartlist_t *BWHistoryReadValues;
struct smartlist_t *BWHistoryReadMaxima;
time_t BWHistoryWriteEnds;
int BWHistoryWriteInterval;
struct smartlist_t *BWHistoryWriteValues;
struct smartlist_t *BWHistoryWriteMaxima;
time_t BWHistoryIPv6ReadEnds;
int BWHistoryIPv6ReadInterval;
struct smartlist_t *BWHistoryIPv6ReadValues;
struct smartlist_t *BWHistoryIPv6ReadMaxima;
time_t BWHistoryIPv6WriteEnds;
int BWHistoryIPv6WriteInterval;
struct smartlist_t *BWHistoryIPv6WriteValues;
struct smartlist_t *BWHistoryIPv6WriteMaxima;
time_t BWHistoryDirReadEnds;
int BWHistoryDirReadInterval;
struct smartlist_t *BWHistoryDirReadValues;
struct smartlist_t *BWHistoryDirReadMaxima;
time_t BWHistoryDirWriteEnds;
int BWHistoryDirWriteInterval;
struct smartlist_t *BWHistoryDirWriteValues;
struct smartlist_t *BWHistoryDirWriteMaxima;
/** Build time histogram */
struct config_line_t * BuildtimeHistogram;
int TotalBuildTimes;
int CircuitBuildAbandonedCount;
/** What version of Tor wrote this state file? */
char *TorVersion;
/** Holds any unrecognized values we found in the state file, in the order
* in which we found them. */
struct config_line_t *ExtraLines;
/** When did we last rotate our onion key? "0" for 'no idea'. */
time_t LastRotatedOnionKey;
/**
* State objects for individual modules.
*
* Never access this field or its members directly: instead, use the module
* in question to get its relevant state object if you must.
*/
struct config_suite_t *substates_;
};
#endif /* !defined(TOR_OR_STATE_ST_H) */
@@ -0,0 +1,30 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file quiet_level.h
* \brief Declare the quiet_level enumeration and global.
**/
#ifndef QUIET_LEVEL_H
#define QUIET_LEVEL_H
/** Enumeration to define how quietly Tor should log at startup. */
typedef enum {
/** Default quiet level: we log everything of level NOTICE or higher. */
QUIET_NONE = 0,
/** "--hush" quiet level: we log everything of level WARNING or higher. */
QUIET_HUSH = 1 ,
/** "--quiet" quiet level: we log nothing at all. */
QUIET_SILENT = 2
} quiet_level_t;
/** How quietly should Tor log at startup? */
extern quiet_level_t quiet_level;
void add_default_log_for_quiet_level(quiet_level_t quiet);
#endif /* !defined(QUIET_LEVEL_H) */
@@ -0,0 +1,67 @@
/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file resolve_addr.h
* \brief Header file for resolve_addr.c.
**/
#ifndef TOR_CONFIG_RESOLVE_ADDR_H
#define TOR_CONFIG_RESOLVE_ADDR_H
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "app/config/or_options_st.h"
/** Method used to resolved an address. In other words, how was the address
* discovered by tor. */
typedef enum {
/* Default value. Indicate that no method found the address. */
RESOLVED_ADDR_NONE = 0,
/* Found from the "Address" configuration option. */
RESOLVED_ADDR_CONFIGURED = 1,
/* Found from the "ORPort" configuration option. */
RESOLVED_ADDR_CONFIGURED_ORPORT = 2,
/* Found by resolving the local hostname. */
RESOLVED_ADDR_GETHOSTNAME = 3,
/* Found by querying the local interface(s). */
RESOLVED_ADDR_INTERFACE = 4,
/* Found by resolving the hostname from the Address configuration option. */
RESOLVED_ADDR_RESOLVED = 5,
} resolved_addr_method_t;
const char *resolved_addr_method_to_str(const resolved_addr_method_t method);
#define get_orport_addr(family) \
(portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, family))
bool find_my_address(const or_options_t *options, int family,
int warn_severity, tor_addr_t *addr_out,
resolved_addr_method_t *method_out, char **hostname_out);
void resolved_addr_get_last(int family, tor_addr_t *addr_out);
void resolved_addr_reset_last(int family);
void resolved_addr_set_last(const tor_addr_t *addr,
const resolved_addr_method_t method_used,
const char *hostname_used);
void resolved_addr_get_suggested(int family, tor_addr_t *addr_out);
void resolved_addr_set_suggested(const tor_addr_t *addr);
bool resolved_addr_is_configured(int family);
MOCK_DECL(bool, is_local_to_resolve_addr, (const tor_addr_t *addr));
#ifdef RESOLVE_ADDR_PRIVATE
#ifdef TOR_UNIT_TESTS
void resolve_addr_reset_suggested(int family);
#endif /* TOR_UNIT_TESTS */
#endif /* defined(RESOLVE_ADDR_PRIVATE) */
#endif /* !defined(TOR_CONFIG_RESOLVE_ADDR_H) */
@@ -0,0 +1,39 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file statefile.h
*
* \brief Header for statefile.c
*/
#ifndef TOR_STATEFILE_H
#define TOR_STATEFILE_H
MOCK_DECL(or_state_t *,get_or_state,(void));
int did_last_state_file_write_fail(void);
int or_state_save(time_t now);
void save_transport_to_state(const char *transport_name,
const tor_addr_t *addr, uint16_t port);
char *get_stored_bindaddr_for_server_transport(const char *transport);
int or_state_load(void);
int or_state_loaded(void);
void or_state_free_all(void);
void or_state_mark_dirty(or_state_t *state, time_t when);
#ifdef STATEFILE_PRIVATE
STATIC struct config_line_t *get_transport_in_state_by_name(
const char *transport);
STATIC void or_state_free_(or_state_t *state);
#define or_state_free(st) FREE_AND_NULL(or_state_t, or_state_free_, (st))
STATIC or_state_t *or_state_new(void);
struct config_mgr_t;
STATIC const struct config_mgr_t *get_state_mgr(void);
STATIC void or_state_remove_obsolete_lines(struct config_line_t **extra_lines);
#endif /* defined(STATEFILE_PRIVATE) */
#endif /* !defined(TOR_STATEFILE_H) */
@@ -0,0 +1,34 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file tor_cmdline_mode.h
* \brief Declare the tor_cmdline_mode_t enumeration
**/
#ifndef TOR_CMDLINE_MODE_H
#define TOR_CMDLINE_MODE_H
/**
* Enumeration to describe which command Tor is running. These commands
* are controlled by command-line options.
**/
typedef enum {
CMD_RUN_TOR=0, /**< The default: run Tor as a daemon. */
CMD_LIST_FINGERPRINT, /**< Running --list-fingerprint. */
CMD_HASH_PASSWORD, /**< Running --hash-password. */
CMD_VERIFY_CONFIG, /**< Running --verify-config. */
CMD_DUMP_CONFIG, /**< Running --dump-config. */
CMD_KEYGEN, /**< Running --keygen */
CMD_KEY_EXPIRATION, /**< Running --key-expiration */
CMD_IMMEDIATE, /**< Special value: indicates a command that is handled
* immediately during configuration processing. */
CMD_RUN_UNITTESTS, /**< Special value: indicates that we have entered
* the Tor code from the unit tests, not from the
* regular Tor binary at all. */
} tor_cmdline_mode_t;
#endif /* !defined(TOR_CMDLINE_MODE_H) */
@@ -0,0 +1,31 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file main.h
* \brief Header file for main.c.
**/
#ifndef TOR_MAIN_H
#define TOR_MAIN_H
void handle_signals(void);
void activate_signal(int signal_num);
int try_locking(const or_options_t *options, int err_if_locked);
int have_lockfile(void);
void release_lockfile(void);
void tor_remove_file(const char *filename);
int tor_init(int argc, char **argv);
int run_tor_main_loop(void);
void pubsub_install(void);
void pubsub_connect(void);
#endif /* !defined(TOR_MAIN_H) */
@@ -0,0 +1,29 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file ntmain.h
* \brief Header file for ntmain.c.
**/
#ifndef TOR_NTMAIN_H
#define TOR_NTMAIN_H
#ifdef _WIN32
#define NT_SERVICE
#endif
#ifdef NT_SERVICE
int nt_service_parse_options(int argc, char **argv, int *should_exit);
int nt_service_is_stopping(void);
void nt_service_set_state(DWORD state);
#else
#define nt_service_is_stopping() 0
#define nt_service_parse_options(a, b, c) (0)
#define nt_service_set_state(s) STMT_NIL
#endif /* defined(NT_SERVICE) */
#endif /* !defined(TOR_NTMAIN_H) */
@@ -0,0 +1,17 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file risky_options.h
* \brief Header for risky_options.c
**/
#ifndef TOR_RISKY_OPTIONS_H
#define TOR_RISKY_OPTIONS_H
extern const char risky_option_list[];
#endif /* !defined(TOR_RISKY_OPTIONS_H) */
@@ -0,0 +1,18 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file shutdown.h
* \brief Header file for shutdown.c.
**/
#ifndef TOR_SHUTDOWN_H
#define TOR_SHUTDOWN_H
void tor_cleanup(void);
void tor_free_all(int postfork);
#endif /* !defined(TOR_SHUTDOWN_H) */
@@ -0,0 +1,53 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file subsysmgr.h
* @brief Header for subsysmgr.c
**/
#ifndef TOR_SUBSYSMGR_T
#define TOR_SUBSYSMGR_T
#include "lib/subsys/subsys.h"
extern const struct subsys_fns_t *tor_subsystems[];
extern const unsigned n_tor_subsystems;
int subsystems_init(void);
int subsystems_init_upto(int level);
struct pubsub_builder_t;
int subsystems_add_pubsub_upto(struct pubsub_builder_t *builder,
int target_level);
int subsystems_add_pubsub(struct pubsub_builder_t *builder);
void subsystems_shutdown(void);
void subsystems_shutdown_downto(int level);
void subsystems_prefork(void);
void subsystems_postfork(void);
void subsystems_thread_cleanup(void);
void subsystems_dump_list(void);
struct config_mgr_t;
int subsystems_register_options_formats(struct config_mgr_t *mgr);
int subsystems_register_state_formats(struct config_mgr_t *mgr);
struct or_options_t;
struct or_state_t;
int subsystems_set_options(const struct config_mgr_t *mgr,
struct or_options_t *options);
int subsystems_set_state(const struct config_mgr_t *mgr,
struct or_state_t *state);
int subsystems_flush_state(const struct config_mgr_t *mgr,
struct or_state_t *state);
#ifdef TOR_UNIT_TESTS
int subsystems_get_options_idx(const subsys_fns_t *sys);
int subsystems_get_state_idx(const subsys_fns_t *sys);
#endif
#endif /* !defined(TOR_SUBSYSMGR_T) */
@@ -0,0 +1,91 @@
/* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file hs_ntor.h
* @brief Header for hs_ntor.c
**/
#ifndef TOR_HS_NTOR_H
#define TOR_HS_NTOR_H
#include "core/or/or.h"
struct ed25519_public_key_t;
struct curve25519_public_key_t;
struct curve25519_keypair_t;
/* Output length of KDF for key expansion */
#define HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN \
(DIGEST256_LEN*2 + CIPHER256_KEY_LEN*2)
/* Key material needed to encode/decode INTRODUCE1 cells */
typedef struct hs_ntor_intro_cell_keys_t {
/* Key used for encryption of encrypted INTRODUCE1 blob */
uint8_t enc_key[CIPHER256_KEY_LEN];
/* MAC key used to protect encrypted INTRODUCE1 blob */
uint8_t mac_key[DIGEST256_LEN];
} hs_ntor_intro_cell_keys_t;
/* Key material needed to encode/decode RENDEZVOUS1 cells */
typedef struct hs_ntor_rend_cell_keys_t {
/* This is the MAC of the HANDSHAKE_INFO field */
uint8_t rend_cell_auth_mac[DIGEST256_LEN];
/* This is the key seed used to derive further rendezvous crypto keys as
* detailed in section 4.2.1 of rend-spec-ng.txt. */
uint8_t ntor_key_seed[DIGEST256_LEN];
} hs_ntor_rend_cell_keys_t;
#define SUBCRED_LEN DIGEST256_LEN
/**
* A 'subcredential' used to prove knowledge of a hidden service.
**/
typedef struct hs_subcredential_t {
uint8_t subcred[SUBCRED_LEN];
} hs_subcredential_t;
int hs_ntor_client_get_introduce1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_public_key_t *intro_enc_pubkey,
const struct curve25519_keypair_t *client_ephemeral_enc_keypair,
const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_client_get_rendezvous1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_keypair_t *client_ephemeral_enc_keypair,
const struct curve25519_public_key_t *intro_enc_pubkey,
const struct curve25519_public_key_t *service_ephemeral_rend_pubkey,
hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out);
int hs_ntor_service_get_introduce1_keys_multi(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_keypair_t *intro_enc_keypair,
const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
size_t n_subcredentials,
const hs_subcredential_t *subcredentials,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_service_get_introduce1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_keypair_t *intro_enc_keypair,
const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_service_get_rendezvous1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_keypair_t *intro_enc_keypair,
const struct curve25519_keypair_t *service_ephemeral_rend_keypair,
const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out);
int hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed,
size_t seed_len,
uint8_t *keys_out, size_t keys_out_len);
int hs_ntor_client_rendezvous2_mac_is_good(
const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys,
const uint8_t *rcvd_mac);
#endif /* !defined(TOR_HS_NTOR_H) */
@@ -0,0 +1,66 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file onion_crypto.h
* \brief Header file for onion_crypto.c.
**/
#ifndef TOR_ONION_CRYPTO_H
#define TOR_ONION_CRYPTO_H
#include "lib/crypt_ops/crypto_ed25519.h"
typedef struct server_onion_keys_t {
uint8_t my_identity[DIGEST_LEN];
ed25519_public_key_t my_ed_identity;
crypto_pk_t *onion_key;
crypto_pk_t *last_onion_key;
struct di_digest256_map_t *curve25519_key_map;
struct curve25519_keypair_t *junk_keypair;
} server_onion_keys_t;
void onion_handshake_state_release(onion_handshake_state_t *state);
/**
* Parameters negotiated as part of a circuit handshake.
*/
typedef struct circuit_params_t {
/** Is true if congestion control is enabled in consensus or param,
* as per congestion_control_enabled() result. */
bool cc_enabled;
/** The number of cells in a sendme increment. Only used if cc_enabled=1. */
uint8_t sendme_inc_cells;
} circuit_params_t;
int onion_skin_create(int type,
const extend_info_t *node,
onion_handshake_state_t *state_out,
uint8_t *onion_skin_out,
size_t onion_skin_out_maxlen);
int onion_skin_server_handshake(int type,
const uint8_t *onion_skin, size_t onionskin_len,
const server_onion_keys_t *keys,
const circuit_params_t *ns_params,
uint8_t *reply_out,
size_t reply_out_maxlen,
uint8_t *keys_out, size_t key_out_len,
uint8_t *rend_nonce_out,
circuit_params_t *negotiated_params_out);
int onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t key_out_len,
uint8_t *rend_authenticator_out,
circuit_params_t *negotiated_params_out,
const char **msg_out);
server_onion_keys_t *server_onion_keys_new(void);
void server_onion_keys_free_(server_onion_keys_t *keys);
#define server_onion_keys_free(keys) \
FREE_AND_NULL(server_onion_keys_t, server_onion_keys_free_, (keys))
#endif /* !defined(TOR_ONION_CRYPTO_H) */
@@ -0,0 +1,41 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file onion_fast.h
* \brief Header file for onion_fast.c.
**/
#ifndef TOR_ONION_FAST_H
#define TOR_ONION_FAST_H
#define CREATE_FAST_LEN DIGEST_LEN
#define CREATED_FAST_LEN (DIGEST_LEN*2)
typedef struct fast_handshake_state_t {
uint8_t state[DIGEST_LEN];
} fast_handshake_state_t;
void fast_handshake_state_free_(fast_handshake_state_t *victim);
#define fast_handshake_state_free(st) \
FREE_AND_NULL(fast_handshake_state_t, fast_handshake_state_free_, (st))
int fast_onionskin_create(fast_handshake_state_t **handshake_state_out,
uint8_t *handshake_out);
int fast_server_handshake(const uint8_t *message_in,
uint8_t *handshake_reply_out,
uint8_t *key_out,
size_t key_out_len);
int fast_client_handshake(const fast_handshake_state_t *handshake_state,
const uint8_t *handshake_reply_out,
uint8_t *key_out,
size_t key_out_len,
const char **msg_out);
#endif /* !defined(TOR_ONION_FAST_H) */
@@ -0,0 +1,70 @@
/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file onion_ntor.h
* @brief Header for onion_ntor.c
**/
#ifndef TOR_ONION_NTOR_H
#define TOR_ONION_NTOR_H
#include "lib/cc/torint.h"
struct di_digest256_map_t;
struct curve25519_public_key_t;
struct curve25519_keypair_t;
/** State to be maintained by a client between sending an ntor onionskin
* and receiving a reply. */
typedef struct ntor_handshake_state_t ntor_handshake_state_t;
/** Length of an ntor onionskin, as sent from the client to server. */
#define NTOR_ONIONSKIN_LEN 84
/** Length of an ntor reply, as sent from server to client. */
#define NTOR_REPLY_LEN 64
void ntor_handshake_state_free_(ntor_handshake_state_t *state);
#define ntor_handshake_state_free(state) \
FREE_AND_NULL(ntor_handshake_state_t, ntor_handshake_state_free_, (state))
int onion_skin_ntor_create(const uint8_t *router_id,
const struct curve25519_public_key_t *router_key,
ntor_handshake_state_t **handshake_state_out,
uint8_t *onion_skin_out);
int onion_skin_ntor_server_handshake(const uint8_t *onion_skin,
const struct di_digest256_map_t *private_keys,
const struct curve25519_keypair_t *junk_keypair,
const uint8_t *my_node_id,
uint8_t *handshake_reply_out,
uint8_t *key_out,
size_t key_out_len);
int onion_skin_ntor_client_handshake(
const ntor_handshake_state_t *handshake_state,
const uint8_t *handshake_reply,
uint8_t *key_out,
size_t key_out_len,
const char **msg_out);
#ifdef ONION_NTOR_PRIVATE
#include "lib/crypt_ops/crypto_curve25519.h"
/** Storage held by a client while waiting for an ntor reply from a server. */
struct ntor_handshake_state_t {
/** Identity digest of the router we're talking to. */
uint8_t router_id[DIGEST_LEN];
/** Onion key of the router we're talking to. */
curve25519_public_key_t pubkey_B;
/**
* Short-lived keypair for use with this handshake.
* @{ */
curve25519_secret_key_t seckey_x;
curve25519_public_key_t pubkey_X;
/** @} */
};
#endif /* defined(ONION_NTOR_PRIVATE) */
#endif /* !defined(TOR_ONION_NTOR_H) */
@@ -0,0 +1,140 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file onion_ntor_v3.h
* @brief Header for core/crypto/onion_ntor_v3.c
**/
#ifndef TOR_CORE_CRYPTO_ONION_NTOR_V3_H
#define TOR_CORE_CRYPTO_ONION_NTOR_V3_H
#include "lib/cc/torint.h"
#include "lib/testsupport/testsupport.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/malloc/malloc.h"
/**
* Client-side state held while an ntor v3 handshake is in progress.
**/
typedef struct ntor3_handshake_state_t ntor3_handshake_state_t;
/**
* Server-side state held while the relay is handling a client's
* encapsulated message, before replying to the v3 handshake.
**/
typedef struct ntor3_server_handshake_state_t ntor3_server_handshake_state_t;
void ntor3_handshake_state_free_(ntor3_handshake_state_t *st);
#define ntor3_handshake_state_free(ptr) \
FREE_AND_NULL(ntor3_handshake_state_t, ntor3_handshake_state_free_, (ptr))
void ntor3_server_handshake_state_free_(ntor3_server_handshake_state_t *st);
#define ntor3_server_handshake_state_free(ptr) \
FREE_AND_NULL(ntor3_server_handshake_state_t, \
ntor3_server_handshake_state_free_, (ptr))
int onion_skin_ntor3_create(const ed25519_public_key_t *relay_id,
const curve25519_public_key_t *relay_key,
const uint8_t *verification,
const size_t verification_len,
const uint8_t *message,
const size_t message_len,
ntor3_handshake_state_t **handshake_state_out,
uint8_t **onion_skin_out,
size_t *onion_skin_len_out);
int onion_ntor3_client_handshake(
const ntor3_handshake_state_t *handshake_state,
const uint8_t *handshake_reply,
size_t reply_len,
const uint8_t *verification,
size_t verification_len,
uint8_t *keys_out,
size_t keys_out_len,
uint8_t **message_out,
size_t *message_len_out);
struct di_digest256_map_t;
int onion_skin_ntor3_server_handshake_part1(
const struct di_digest256_map_t *private_keys,
const curve25519_keypair_t *junk_key,
const ed25519_public_key_t *my_id,
const uint8_t *client_handshake,
size_t client_handshake_len,
const uint8_t *verification,
size_t verification_len,
uint8_t **client_message_out,
size_t *client_message_len_out,
ntor3_server_handshake_state_t **state_out);
int onion_skin_ntor3_server_handshake_part2(
const ntor3_server_handshake_state_t *state,
const uint8_t *verification,
size_t verification_len,
const uint8_t *server_message,
size_t server_message_len,
uint8_t **handshake_out,
size_t *handshake_len_out,
uint8_t *keys_out,
size_t keys_out_len);
#ifdef ONION_NTOR_V3_PRIVATE
struct ntor3_handshake_state_t {
/** Ephemeral (x,X) keypair. */
curve25519_keypair_t client_keypair;
/** Relay's ed25519 identity key (ID) */
ed25519_public_key_t relay_id;
/** Relay's public key (B) */
curve25519_public_key_t relay_key;
/** Shared secret (Bx). */
uint8_t bx[CURVE25519_OUTPUT_LEN];
/** MAC of the client's encrypted message data (MAC) */
uint8_t msg_mac[DIGEST256_LEN];
};
struct ntor3_server_handshake_state_t {
/** Relay's ed25519 identity key (ID) */
ed25519_public_key_t my_id;
/** Relay's public key (B) */
curve25519_public_key_t my_key;
/** Client's public ephemeral key (X). */
curve25519_public_key_t client_key;
/** Shared secret (Xb) */
uint8_t xb[CURVE25519_OUTPUT_LEN];
/** MAC of the client's encrypted message data */
uint8_t msg_mac[DIGEST256_LEN];
};
STATIC int onion_skin_ntor3_create_nokeygen(
const curve25519_keypair_t *client_keypair,
const ed25519_public_key_t *relay_id,
const curve25519_public_key_t *relay_key,
const uint8_t *verification,
const size_t verification_len,
const uint8_t *message,
const size_t message_len,
ntor3_handshake_state_t **handshake_state_out,
uint8_t **onion_skin_out,
size_t *onion_skin_len_out);
STATIC int onion_skin_ntor3_server_handshake_part2_nokeygen(
const curve25519_keypair_t *relay_keypair_y,
const ntor3_server_handshake_state_t *state,
const uint8_t *verification,
size_t verification_len,
const uint8_t *server_message,
size_t server_message_len,
uint8_t **handshake_out,
size_t *handshake_len_out,
uint8_t *keys_out,
size_t keys_out_len);
#endif
#endif /* !defined(TOR_CORE_CRYPTO_ONION_NTOR_V3_H) */
@@ -0,0 +1,40 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file onion_tap.h
* \brief Header file for onion_tap.c.
**/
#ifndef TOR_ONION_TAP_H
#define TOR_ONION_TAP_H
#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
CIPHER_KEY_LEN+\
DH1024_KEY_LEN)
#define TAP_ONIONSKIN_REPLY_LEN (DH1024_KEY_LEN+DIGEST_LEN)
struct crypto_dh_t;
struct crypto_pk_t;
int onion_skin_TAP_create(struct crypto_pk_t *router_key,
struct crypto_dh_t **handshake_state_out,
char *onion_skin_out);
int onion_skin_TAP_server_handshake(const char *onion_skin,
struct crypto_pk_t *private_key,
struct crypto_pk_t *prev_private_key,
char *handshake_reply_out,
char *key_out,
size_t key_out_len);
int onion_skin_TAP_client_handshake(struct crypto_dh_t *handshake_state,
const char *handshake_reply,
char *key_out,
size_t key_out_len,
const char **msg_out);
#endif /* !defined(TOR_ONION_TAP_H) */
@@ -0,0 +1,42 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file relay.h
* \brief Header file for relay.c.
**/
#ifndef TOR_RELAY_CRYPTO_H
#define TOR_RELAY_CRYPTO_H
int relay_crypto_init(relay_crypto_t *crypto,
const char *key_data, size_t key_data_len,
int reverse, int is_hs_v3);
int relay_decrypt_cell(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
crypt_path_t **layer_hint, char *recognized);
void relay_encrypt_cell_outbound(cell_t *cell, origin_circuit_t *or_circ,
crypt_path_t *layer_hint);
void relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ);
void relay_crypto_clear(relay_crypto_t *crypto);
void relay_crypto_assert_ok(const relay_crypto_t *crypto);
uint8_t *relay_crypto_get_sendme_digest(relay_crypto_t *crypto);
void relay_crypto_record_sendme_digest(relay_crypto_t *crypto,
bool is_foward_digest);
void
relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in);
void
relay_set_digest(crypto_digest_t *digest, cell_t *cell);
#endif /* !defined(TOR_RELAY_CRYPTO_H) */
@@ -0,0 +1,396 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file connection.h
* \brief Header file for connection.c.
**/
#ifndef TOR_CONNECTION_H
#define TOR_CONNECTION_H
#include "lib/smartlist_core/smartlist_core.h"
#include "lib/log/log.h"
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
struct listener_connection_t;
struct connection_t;
struct dir_connection_t;
struct or_connection_t;
struct edge_connection_t;
struct entry_connection_t;
struct control_connection_t;
struct port_cfg_t;
struct tor_addr_t;
struct or_options_t;
struct listener_connection_t *TO_LISTENER_CONN(struct connection_t *);
const struct listener_connection_t *CONST_TO_LISTENER_CONN(
const struct connection_t *);
struct buf_t;
#define CONN_TYPE_MIN_ 3
/** Type for sockets listening for OR connections. */
#define CONN_TYPE_OR_LISTENER 3
/** A bidirectional TLS connection transmitting a sequence of cells.
* May be from an OR to an OR, or from an OP to an OR. */
#define CONN_TYPE_OR 4
/** A TCP connection from an onion router to a stream's destination. */
#define CONN_TYPE_EXIT 5
/** Type for sockets listening for SOCKS connections. */
#define CONN_TYPE_AP_LISTENER 6
/** A SOCKS proxy connection from the user application to the onion
* proxy. */
#define CONN_TYPE_AP 7
/** Type for sockets listening for HTTP connections to the directory server. */
#define CONN_TYPE_DIR_LISTENER 8
/** Type for HTTP connections to the directory server. */
#define CONN_TYPE_DIR 9
/* Type 10 is unused. */
/** Type for listening for connections from user interface process. */
#define CONN_TYPE_CONTROL_LISTENER 11
/** Type for connections from user interface process. */
#define CONN_TYPE_CONTROL 12
/** Type for sockets listening for transparent connections redirected by pf or
* netfilter. */
#define CONN_TYPE_AP_TRANS_LISTENER 13
/** Type for sockets listening for transparent connections redirected by
* natd. */
#define CONN_TYPE_AP_NATD_LISTENER 14
/** Type for sockets listening for DNS requests. */
#define CONN_TYPE_AP_DNS_LISTENER 15
/** Type for connections from the Extended ORPort. */
#define CONN_TYPE_EXT_OR 16
/** Type for sockets listening for Extended ORPort connections. */
#define CONN_TYPE_EXT_OR_LISTENER 17
/** Type for sockets listening for HTTP CONNECT tunnel connections. */
#define CONN_TYPE_AP_HTTP_CONNECT_LISTENER 18
/** Type for sockets listening for Metrics query connections. */
#define CONN_TYPE_METRICS_LISTENER 19
/** Type for connections from metrics listener. */
#define CONN_TYPE_METRICS 20
#define CONN_TYPE_MAX_ 21
/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
* struct connection_t. */
/* Proxy client handshake states */
/* We use a proxy but we haven't even connected to it yet. */
#define PROXY_INFANT 1
/* We use an HTTP proxy and we've sent the CONNECT command. */
#define PROXY_HTTPS_WANT_CONNECT_OK 2
/* We use a SOCKS4 proxy and we've sent the CONNECT command. */
#define PROXY_SOCKS4_WANT_CONNECT_OK 3
/* We use a SOCKS5 proxy and we try to negotiate without
any authentication . */
#define PROXY_SOCKS5_WANT_AUTH_METHOD_NONE 4
/* We use a SOCKS5 proxy and we try to negotiate with
Username/Password authentication . */
#define PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929 5
/* We use a SOCKS5 proxy and we just sent our credentials. */
#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6
/* We use a SOCKS5 proxy and we just sent our CONNECT command. */
#define PROXY_SOCKS5_WANT_CONNECT_OK 7
/* We use an HAPROXY proxy and we just sent the proxy header. */
#define PROXY_HAPROXY_WAIT_FOR_FLUSH 8
/* We use a proxy and we CONNECTed successfully!. */
#define PROXY_CONNECTED 9
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
/**
* This struct associates an old listener connection to be replaced
* by new connection described by port configuration. Only used when
* moving listeners to/from wildcard IP address.
*/
typedef struct
{
struct connection_t *old_conn; /* Old listener connection to be replaced */
const struct port_cfg_t *new_port; /* New port configuration */
} listener_replacement_t;
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
int conn_listener_type_supports_af_unix(int type);
const char *connection_describe(const connection_t *conn);
const char *connection_describe_peer(const connection_t *conn);
struct dir_connection_t *dir_connection_new(int socket_family);
struct or_connection_t *or_connection_new(int type, int socket_family);
struct edge_connection_t *edge_connection_new(int type, int socket_family);
struct entry_connection_t *entry_connection_new(int type, int socket_family);
struct control_connection_t *control_connection_new(int socket_family);
struct listener_connection_t *listener_connection_new(int type,
int socket_family);
struct connection_t *connection_new(int type, int socket_family);
int connection_init_accepted_conn(struct connection_t *conn,
const struct listener_connection_t *listener);
void connection_link_connections(struct connection_t *conn_a,
struct connection_t *conn_b);
MOCK_DECL(void,connection_free_,(struct connection_t *conn));
#define connection_free(conn) \
FREE_AND_NULL(struct connection_t, connection_free_, (conn))
void connection_free_all(void);
void connection_about_to_close_connection(struct connection_t *conn);
void connection_close_immediate(struct connection_t *conn);
void connection_mark_for_close_(struct connection_t *conn,
int line, const char *file);
MOCK_DECL(void, connection_mark_for_close_internal_,
(struct connection_t *conn, int line, const char *file));
#define connection_mark_for_close(c) \
connection_mark_for_close_((c), __LINE__, SHORT_FILE__)
#define connection_mark_for_close_internal(c) \
connection_mark_for_close_internal_((c), __LINE__, SHORT_FILE__)
/**
* Mark 'c' for close, but try to hold it open until all the data is written.
* Use the _internal versions of connection_mark_for_close; this should be
* called when you either are sure that if this is an or_connection_t the
* controlling channel has been notified (e.g. with
* connection_or_notify_error()), or you actually are the
* connection_or_close_for_error() or connection_or_close_normally function.
* For all other cases, use connection_mark_and_flush() instead, which
* checks for struct or_connection_t properly, instead. See below.
*/
#define connection_mark_and_flush_internal_(c,line,file) \
do { \
struct connection_t *tmp_conn__ = (c); \
connection_mark_for_close_internal_(tmp_conn__, (line), (file)); \
tmp_conn__->hold_open_until_flushed = 1; \
} while (0)
#define connection_mark_and_flush_internal(c) \
connection_mark_and_flush_internal_((c), __LINE__, SHORT_FILE__)
/**
* Mark 'c' for close, but try to hold it open until all the data is written.
*/
#define connection_mark_and_flush_(c,line,file) \
do { \
struct connection_t *tmp_conn_ = (c); \
if (tmp_conn_->type == CONN_TYPE_OR) { \
log_warn(LD_CHANNEL | LD_BUG, \
"Something tried to close (and flush) an or_connection_t" \
" without going through channels at %s:%d", \
file, line); \
connection_or_close_for_error(TO_OR_CONN(tmp_conn_), 1); \
} else { \
connection_mark_and_flush_internal_(c, line, file); \
} \
} while (0)
#define connection_mark_and_flush(c) \
connection_mark_and_flush_((c), __LINE__, SHORT_FILE__)
void connection_expire_held_open(void);
int connection_connect(struct connection_t *conn, const char *address,
const struct tor_addr_t *addr,
uint16_t port, int *socket_error);
#ifdef HAVE_SYS_UN_H
int connection_connect_unix(struct connection_t *conn, const char *socket_path,
int *socket_error);
#endif /* defined(HAVE_SYS_UN_H) */
/** Maximum size of information that we can fit into SOCKS5 username
or password fields. */
#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
/** Total maximum size of information that we can fit into SOCKS5
username and password fields. */
#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE
int connection_proxy_connect(struct connection_t *conn, int type);
int connection_read_proxy_handshake(struct connection_t *conn);
void log_failed_proxy_connection(struct connection_t *conn);
int get_proxy_addrport(struct tor_addr_t *addr, uint16_t *port,
int *proxy_type,
int *is_pt_out, const struct connection_t *conn);
int retry_all_listeners(struct smartlist_t *new_conns,
int close_all_noncontrol);
void connection_mark_all_noncontrol_listeners(void);
void connection_mark_all_noncontrol_connections(void);
ssize_t connection_bucket_write_limit(struct connection_t *conn, time_t now);
bool connection_dir_is_global_write_low(const struct connection_t *conn,
size_t attempt);
void connection_bucket_init(void);
void connection_bucket_adjust(const struct or_options_t *options);
void connection_bucket_refill_all(time_t now,
uint32_t now_ts);
void connection_read_bw_exhausted(struct connection_t *conn,
bool is_global_bw);
void connection_write_bw_exhausted(struct connection_t *conn,
bool is_global_bw);
void connection_consider_empty_read_buckets(struct connection_t *conn);
void connection_consider_empty_write_buckets(struct connection_t *conn);
int connection_handle_read(struct connection_t *conn);
int connection_buf_get_bytes(char *string, size_t len,
struct connection_t *conn);
int connection_buf_get_line(struct connection_t *conn, char *data,
size_t *data_len);
int connection_fetch_from_buf_http(struct connection_t *conn,
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used,
size_t max_bodylen, int force_complete);
int connection_wants_to_flush(struct connection_t *conn);
int connection_outbuf_too_full(struct connection_t *conn);
int connection_handle_write(struct connection_t *conn, int force);
int connection_flush(struct connection_t *conn);
int connection_process_inbuf(struct connection_t *conn, int package_partial);
MOCK_DECL(void, connection_write_to_buf_impl_,
(const char *string, size_t len, struct connection_t *conn,
int zlib));
/* DOCDOC connection_write_to_buf */
static void connection_buf_add(const char *string, size_t len,
struct connection_t *conn);
void connection_dir_buf_add(const char *string, size_t len,
struct dir_connection_t *dir_conn, int done);
static inline void
connection_buf_add(const char *string, size_t len, struct connection_t *conn)
{
connection_write_to_buf_impl_(string, len, conn, 0);
}
void connection_buf_add_compress(const char *string, size_t len,
struct dir_connection_t *conn, int done);
void connection_buf_add_buf(struct connection_t *conn, struct buf_t *buf);
size_t connection_get_inbuf_len(const struct connection_t *conn);
size_t connection_get_outbuf_len(const struct connection_t *conn);
struct connection_t *connection_get_by_global_id(uint64_t id);
struct connection_t *connection_get_by_type(int type);
MOCK_DECL(struct connection_t *,connection_get_by_type_nonlinked,(int type));
MOCK_DECL(struct connection_t *,connection_get_by_type_addr_port_purpose,
(int type,
const struct tor_addr_t *addr,
uint16_t port, int purpose));
struct connection_t *connection_get_by_type_state(int type, int state);
struct connection_t *connection_get_by_type_state_rendquery(
int type, int state,
const char *rendquery);
struct smartlist_t *connection_list_by_type_state(int type, int state);
struct smartlist_t *connection_list_by_type_purpose(int type, int purpose);
struct smartlist_t *connection_dir_list_by_purpose_and_resource(
int purpose,
const char *resource);
struct smartlist_t *connection_dir_list_by_purpose_resource_and_state(
int purpose,
const char *resource,
int state);
#define CONN_LEN_AND_FREE_TEMPLATE(sl) \
STMT_BEGIN \
int len = smartlist_len(sl); \
smartlist_free(sl); \
return len; \
STMT_END
/** Return a count of directory connections that are fetching the item
* described by <b>purpose</b>/<b>resource</b>. */
static inline int
connection_dir_count_by_purpose_and_resource(
int purpose,
const char *resource)
{
struct smartlist_t *conns = connection_dir_list_by_purpose_and_resource(
purpose,
resource);
CONN_LEN_AND_FREE_TEMPLATE(conns);
}
/** Return a count of directory connections that are fetching the item
* described by <b>purpose</b>/<b>resource</b>/<b>state</b>. */
static inline int
connection_dir_count_by_purpose_resource_and_state(
int purpose,
const char *resource,
int state)
{
struct smartlist_t *conns =
connection_dir_list_by_purpose_resource_and_state(
purpose,
resource,
state);
CONN_LEN_AND_FREE_TEMPLATE(conns);
}
#undef CONN_LEN_AND_FREE_TEMPLATE
int any_other_active_or_conns(const struct or_connection_t *this_conn);
/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define connection_speaks_cells(conn) (((conn)->type == CONN_TYPE_OR) || 0)
int connection_is_listener(struct connection_t *conn);
int connection_state_is_open(struct connection_t *conn);
int connection_state_is_connecting(struct connection_t *conn);
char *alloc_http_authenticator(const char *authenticator);
void assert_connection_ok(struct connection_t *conn, time_t now);
int connection_or_nonopen_was_started_here(struct or_connection_t *conn);
void connection_dump_buffer_mem_stats(int severity);
MOCK_DECL(void, clock_skew_warning,
(const struct connection_t *conn, long apparent_skew, int trusted,
log_domain_mask_t domain, const char *received,
const char *source));
int connection_is_moribund(struct connection_t *conn);
void connection_check_oos(int n_socks, int failed);
/** Execute the statement <b>stmt</b>, which may log events concerning the
* connection <b>conn</b>. To prevent infinite loops, disable log messages
* being sent to controllers if <b>conn</b> is a control connection.
*
* Stmt must not contain any return or goto statements.
*/
#define CONN_LOG_PROTECT(conn, stmt) \
STMT_BEGIN \
int _log_conn_is_control; \
tor_assert(conn); \
_log_conn_is_control = (conn->type == CONN_TYPE_CONTROL); \
if (_log_conn_is_control) \
disable_control_logging(); \
STMT_BEGIN stmt; STMT_END; \
if (_log_conn_is_control) \
enable_control_logging(); \
STMT_END
#ifdef CONNECTION_PRIVATE
STATIC void connection_free_minimal(struct connection_t *conn);
/* Used only by connection.c and test*.c */
MOCK_DECL(STATIC int,connection_connect_sockaddr,
(struct connection_t *conn,
const struct sockaddr *sa,
socklen_t sa_len,
const struct sockaddr *bindaddr,
socklen_t bindaddr_len,
int *socket_error));
MOCK_DECL(STATIC void, kill_conn_list_for_oos, (struct smartlist_t *conns));
MOCK_DECL(STATIC struct smartlist_t *, pick_oos_victims, (int n));
#endif /* defined(CONNECTION_PRIVATE) */
#endif /* !defined(TOR_CONNECTION_H) */
@@ -0,0 +1,43 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2024, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file cpuworker.h
* \brief Header file for cpuworker.c.
**/
#ifndef TOR_CPUWORKER_H
#define TOR_CPUWORKER_H
int cpuworker_init(void);
void cpuworker_free_all(void);
void cpuworkers_rotate_keyinfo(void);
void cpuworker_consensus_has_changed(const networkstatus_t *ns);
struct workqueue_entry_t;
enum workqueue_reply_t;
enum workqueue_priority_t;
MOCK_DECL(struct workqueue_entry_t *, cpuworker_queue_work, (
enum workqueue_priority_t priority,
enum workqueue_reply_t (*fn)(void *, void *),
void (*reply_fn)(void *),
void *arg));
struct create_cell_t;
int assign_onionskin_to_cpuworker(or_circuit_t *circ,
struct create_cell_t *onionskin);
uint64_t estimated_usec_for_onionskins(uint32_t n_requests,
uint16_t onionskin_type);
void cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
const char *onionskin_type_name);
void cpuworker_cancel_circ_handshake(or_circuit_t *circ);
unsigned int cpuworker_get_n_threads(void);
#endif /* !defined(TOR_CPUWORKER_H) */
@@ -0,0 +1,117 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file mainloop.h
* \brief Header file for mainloop.c.
**/
#ifndef TOR_MAINLOOP_H
#define TOR_MAINLOOP_H
int have_completed_a_circuit(void);
void note_that_we_completed_a_circuit(void);
void note_that_we_maybe_cant_complete_circuits(void);
int connection_add_impl(connection_t *conn, int is_connecting);
#define connection_add(conn) connection_add_impl((conn), 0)
#define connection_add_connecting(conn) connection_add_impl((conn), 1)
int connection_remove(connection_t *conn);
void connection_unregister_events(connection_t *conn);
int connection_in_array(connection_t *conn);
void add_connection_to_closeable_list(connection_t *conn);
int connection_is_on_closeable_list(connection_t *conn);
MOCK_DECL(smartlist_t *, get_connection_array, (void));
MOCK_DECL(uint64_t,get_bytes_read,(void));
MOCK_DECL(uint64_t,get_bytes_written,(void));
void stats_increment_bytes_read_and_written(uint64_t r, uint64_t w);
/** Bitmask for events that we can turn on and off with
* connection_watch_events. */
typedef enum watchable_events {
/* Yes, it is intentional that these match Libevent's EV_READ and EV_WRITE */
READ_EVENT=0x02, /**< We want to know when a connection is readable */
WRITE_EVENT=0x04 /**< We want to know when a connection is writable */
} watchable_events_t;
void connection_watch_events(connection_t *conn, watchable_events_t events);
int connection_is_reading(const connection_t *conn);
MOCK_DECL(void,connection_stop_reading,(connection_t *conn));
MOCK_DECL(void,connection_start_reading,(connection_t *conn));
int connection_is_writing(connection_t *conn);
MOCK_DECL(void,connection_stop_writing,(connection_t *conn));
MOCK_DECL(void,connection_start_writing,(connection_t *conn));
void tor_shutdown_event_loop_and_exit(int exitcode);
int tor_event_loop_shutdown_is_pending(void);
void connection_stop_reading_from_linked_conn(connection_t *conn);
MOCK_DECL(int, connection_count_moribund, (void));
void directory_all_unreachable(time_t now);
void directory_info_has_arrived(time_t now, int from_cache, int suppress_logs);
void ip_address_changed(int on_client_conn);
void dns_servers_relaunch_checks(void);
void reset_all_main_loop_timers(void);
void reschedule_directory_downloads(void);
void reschedule_or_state_save(void);
void mainloop_schedule_postloop_cleanup(void);
void rescan_periodic_events(const or_options_t *options);
MOCK_DECL(void, schedule_rescan_periodic_events,(void));
void update_current_time(time_t now);
MOCK_DECL(long,get_uptime,(void));
MOCK_DECL(void,reset_uptime,(void));
unsigned get_signewnym_epoch(void);
int do_main_loop(void);
void reset_main_loop_counters(void);
uint64_t get_main_loop_success_count(void);
uint64_t get_main_loop_error_count(void);
uint64_t get_main_loop_idle_count(void);
void periodic_events_on_new_options(const or_options_t *options);
void do_signewnym(time_t);
time_t get_last_signewnym_time(void);
void mainloop_schedule_shutdown(int delay_sec);
void tor_init_connection_lists(void);
void initialize_mainloop_events(void);
void initialize_periodic_events(void);
void tor_mainloop_free_all(void);
struct token_bucket_rw_t;
extern time_t time_of_process_start;
extern struct token_bucket_rw_t global_bucket;
extern struct token_bucket_rw_t global_relayed_bucket;
#ifdef MAINLOOP_PRIVATE
STATIC int run_main_loop_until_done(void);
STATIC void close_closeable_connections(void);
STATIC void teardown_periodic_events(void);
STATIC int get_my_roles(const or_options_t *);
STATIC int check_network_participation_callback(time_t now,
const or_options_t *options);
#ifdef TOR_UNIT_TESTS
extern smartlist_t *connection_array;
/* We need the periodic_event_item_t definition. */
#include "core/mainloop/periodic.h"
extern periodic_event_item_t mainloop_periodic_events[];
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(MAINLOOP_PRIVATE) */
#endif /* !defined(TOR_MAINLOOP_H) */
@@ -0,0 +1,61 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file mainloop_pubsub.h
* @brief Header for mainloop_pubsub.c
**/
#ifndef TOR_MAINLOOP_PUBSUB_H
#define TOR_MAINLOOP_PUBSUB_H
struct pubsub_builder_t;
/**
* Describe when and how messages are delivered on message channel.
*
* Every message channel must be associated with one of these strategies.
**/
typedef enum {
/**
* Never deliver messages automatically.
*
* If a message channel uses this strategy, then no matter now many
* messages are published on it, they are not delivered until something
* manually calls dispatch_flush() for that channel
**/
DELIV_NEVER=0,
/**
* Deliver messages promptly, via the event loop.
*
* If a message channel uses this strategy, then publishing a messages
* that channel activates an event that causes messages to be handled
* later in the mainloop. The messages will be processed at some point
* very soon, delaying only for pending IO events and the like.
*
* Generally this is the best choice for a delivery strategy, since
* it avoids stack explosion.
**/
DELIV_PROMPT,
/**
* Deliver messages immediately, skipping the event loop.
*
* Every event on this channel is flushed immediately after it is queued,
* using the stack.
*
* This delivery type should be used with caution, since it can cause
* unexpected call chains, resource starvation, and the like.
**/
DELIV_IMMEDIATE,
} deliv_strategy_t;
int tor_mainloop_connect_pubsub(struct pubsub_builder_t *builder);
void tor_mainloop_connect_pubsub_events(void);
int tor_mainloop_set_delivery_strategy(const char *msg_channel_name,
deliv_strategy_t strategy);
void tor_mainloop_disconnect_pubsub(void);
#endif /* !defined(TOR_MAINLOOP_PUBSUB_H) */
@@ -0,0 +1,23 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file mainloop_state_st.h
* @brief Declare a state structure for mainloop-relevant fields
**/
#ifndef TOR_CORE_MAINLOOP_MAINLOOP_STATE_ST_H
#define TOR_CORE_MAINLOOP_MAINLOOP_STATE_ST_H
#include "lib/conf/confdecl.h"
#define CONF_CONTEXT STRUCT
#include "core/mainloop/mainloop_state.inc"
#undef CONF_CONTEXT
typedef struct mainloop_state_t mainloop_state_t;
#endif /* !defined(TOR_CORE_MAINLOOP_MAINLOOP_STATE_ST_H) */
@@ -0,0 +1,17 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file mainloop_sys.h
* @brief Header for mainloop_sys.c
**/
#ifndef MAINLOOP_SYS_H
#define MAINLOOP_SYS_H
extern const struct subsys_fns_t sys_mainloop;
#endif /* !defined(MAINLOOP_SYS_H) */
@@ -0,0 +1,32 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file netstatus.h
* @brief Header for netstatus.c
**/
#ifndef TOR_NETSTATUS_H
#define TOR_NETSTATUS_H
int net_is_disabled(void);
int net_is_completely_disabled(void);
void note_user_activity(time_t now);
void reset_user_activity(time_t now);
time_t get_last_user_activity_time(void);
void set_network_participation(bool participation);
bool is_participating_on_network(void);
struct mainloop_state_t;
void netstatus_flush_to_state(struct mainloop_state_t *state, time_t now);
void netstatus_load_from_state(const struct mainloop_state_t *state,
time_t now);
void netstatus_note_clock_jumped(time_t seconds_diff);
#endif /* !defined(TOR_NETSTATUS_H) */
@@ -0,0 +1,109 @@
/* Copyright (c) 2015-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file periodic.h
* @brief Header for periodic.c
**/
#ifndef TOR_PERIODIC_H
#define TOR_PERIODIC_H
#define PERIODIC_EVENT_NO_UPDATE (-1)
/* Tor roles for which a periodic event item is for. An event can be for
* multiple roles, they can be combined. */
#define PERIODIC_EVENT_ROLE_CLIENT (1U << 0)
#define PERIODIC_EVENT_ROLE_RELAY (1U << 1)
#define PERIODIC_EVENT_ROLE_BRIDGE (1U << 2)
#define PERIODIC_EVENT_ROLE_DIRAUTH (1U << 3)
#define PERIODIC_EVENT_ROLE_BRIDGEAUTH (1U << 4)
#define PERIODIC_EVENT_ROLE_HS_SERVICE (1U << 5)
#define PERIODIC_EVENT_ROLE_DIRSERVER (1U << 6)
#define PERIODIC_EVENT_ROLE_CONTROLEV (1U << 7)
#define PERIODIC_EVENT_ROLE_NET_PARTICIPANT (1U << 8)
#define PERIODIC_EVENT_ROLE_ALL (1U << 9)
/* Helper macro to make it a bit less annoying to defined groups of roles that
* are often used. */
/* Router that is a Bridge or Relay. */
#define PERIODIC_EVENT_ROLE_ROUTER \
(PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_RELAY)
/* Authorities that is both bridge and directory. */
#define PERIODIC_EVENT_ROLE_AUTHORITIES \
(PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_DIRAUTH)
/*
* Event flags which can change the behavior of an event.
*/
/* Indicate that the event needs the network meaning that if we are in
* DisableNetwork or hibernation mode, the event won't be enabled. This obey
* the net_is_disabled() check. */
#define PERIODIC_EVENT_FLAG_NEED_NET (1U << 0)
/* Indicate that if the event is enabled, it needs to be run once before
* it becomes disabled.
*/
#define PERIODIC_EVENT_FLAG_RUN_ON_DISABLE (1U << 1)
/** Callback function for a periodic event to take action. The return value
* influences the next time the function will get called. Return
* PERIODIC_EVENT_NO_UPDATE to not update <b>last_action_time</b> and be polled
* again in the next second. If a positive value is returned it will update the
* interval time. */
typedef int (*periodic_event_helper_t)(time_t now,
const or_options_t *options);
struct mainloop_event_t;
/** A single item for the periodic-events-function table. */
typedef struct periodic_event_item_t {
periodic_event_helper_t fn; /**< The function to run the event */
time_t last_action_time; /**< The last time the function did something */
struct mainloop_event_t *ev; /**< Libevent callback we're using to implement
* this */
const char *name; /**< Name of the function -- for debug */
/* Bitmask of roles define above for which this event applies. */
uint32_t roles;
/* Bitmask of flags which can change the behavior of the event. */
uint32_t flags;
/* Indicate that this event has been enabled that is scheduled. */
unsigned int enabled : 1;
} periodic_event_item_t;
/** events will get their interval from first execution */
#ifndef COCCI
#define PERIODIC_EVENT(fn, r, f) { fn##_callback, 0, NULL, #fn, r, f, 0 }
#define END_OF_PERIODIC_EVENTS { NULL, 0, NULL, NULL, 0, 0, 0 }
#endif
/* Return true iff the given event was setup before thus is enabled to be
* scheduled. */
static inline int
periodic_event_is_enabled(const periodic_event_item_t *item)
{
return item->enabled;
}
void periodic_event_launch(periodic_event_item_t *event);
void periodic_event_connect(periodic_event_item_t *event);
//void periodic_event_disconnect(periodic_event_item_t *event);
void periodic_event_reschedule(periodic_event_item_t *event);
void periodic_event_enable(periodic_event_item_t *event);
void periodic_event_disable(periodic_event_item_t *event);
void periodic_event_schedule_and_disable(periodic_event_item_t *event);
void periodic_events_register(periodic_event_item_t *item);
void periodic_events_connect_all(void);
void periodic_events_reset_all(void);
periodic_event_item_t *periodic_events_find(const char *name);
void periodic_events_rescan_by_roles(int roles, bool net_disabled);
void periodic_events_disconnect_all(void);
int safe_timer_diff(time_t now, time_t next);
#endif /* !defined(TOR_PERIODIC_H) */
@@ -0,0 +1,51 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file addr_policy_st.h
* @brief Address policy structures.
**/
#ifndef TOR_ADDR_POLICY_ST_H
#define TOR_ADDR_POLICY_ST_H
#include "lib/cc/torint.h"
#include "lib/net/address.h"
/** What action type does an address policy indicate: accept or reject? */
typedef enum {
ADDR_POLICY_ACCEPT=1,
ADDR_POLICY_REJECT=2,
} addr_policy_action_t;
#define addr_policy_action_bitfield_t ENUM_BF(addr_policy_action_t)
/** A reference-counted address policy rule. */
struct addr_policy_t {
int refcnt; /**< Reference count */
/** What to do when the policy matches.*/
addr_policy_action_bitfield_t policy_type:2;
unsigned int is_private:1; /**< True iff this is the pseudo-address,
* "private". */
unsigned int is_canonical:1; /**< True iff this policy is the canonical
* copy (stored in a hash table to avoid
* duplication of common policies) */
maskbits_t maskbits; /**< Accept/reject all addresses <b>a</b> such that the
* first <b>maskbits</b> bits of <b>a</b> match
* <b>addr</b>. */
/** Base address to accept or reject.
*
* Note that wildcards are treated
* differently depending on address family. An AF_UNSPEC address means
* "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means
* "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means
* "All IPv6 addresses".
**/
tor_addr_t addr;
uint16_t prt_min; /**< Lowest port number to accept/reject. */
uint16_t prt_max; /**< Highest port number to accept/reject. */
};
#endif /* !defined(TOR_ADDR_POLICY_ST_H) */
@@ -0,0 +1,32 @@
/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file address_set.h
* \brief Types to handle sets of addresses.
**/
#ifndef TOR_ADDRESS_SET_H
#define TOR_ADDRESS_SET_H
#include "orconfig.h"
#include "lib/cc/torint.h"
#include "lib/container/bloomfilt.h"
struct tor_addr_t;
/**
* An address_set_t represents a set of tor_addr_t values. The implementation
* is probabilistic: false negatives cannot occur but false positives are
* possible.
*/
typedef struct bloomfilt_t address_set_t;
address_set_t *address_set_new(int max_addresses_guess);
#define address_set_free(set) bloomfilt_free(set)
void address_set_add(address_set_t *set, const struct tor_addr_t *addr);
void address_set_add_ipv4h(address_set_t *set, uint32_t addr);
int address_set_probably_contains(const address_set_t *set,
const struct tor_addr_t *addr);
#endif /* !defined(TOR_ADDRESS_SET_H) */
@@ -0,0 +1,34 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file cell_queue_st.h
* @brief Cell queue structures
**/
#ifndef PACKED_CELL_ST_H
#define PACKED_CELL_ST_H
#include "tor_queue.h"
/** A cell as packed for writing to the network. */
struct packed_cell_t {
/** Next cell queued on this circuit. */
TOR_SIMPLEQ_ENTRY(packed_cell_t) next;
char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */
uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell
* was inserted */
};
/** A queue of cells on a circuit, waiting to be added to the
* or_connection_t's outbuf. */
struct cell_queue_t {
/** Linked list of packed_cell_t*/
TOR_SIMPLEQ_HEAD(cell_simpleq_t, packed_cell_t) head;
int n; /**< The number of cells in the queue. */
};
#endif /* !defined(PACKED_CELL_ST_H) */
@@ -0,0 +1,24 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file cell_st.h
* @brief Fixed-size cell structure.
**/
#ifndef CELL_ST_H
#define CELL_ST_H
/** Parsed onion routing cell. All communication between nodes
* is via cells. */
struct cell_t {
circid_t circ_id; /**< Circuit which received the cell. */
uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE,
* CELL_DESTROY, etc */
uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */
};
#endif /* !defined(CELL_ST_H) */
@@ -0,0 +1,775 @@
/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file channel.h
* \brief Header file for channel.c
**/
#ifndef TOR_CHANNEL_H
#define TOR_CHANNEL_H
#include "core/or/or.h"
#include "core/or/circuitmux.h"
#include "lib/container/handles.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "ext/ht.h"
#include "tor_queue.h"
#define tor_timer_t timeout
struct tor_timer_t;
/* Channel handler function pointer typedefs */
typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *);
typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
/**
* This enum is used by channelpadding to decide when to pad channels.
* Don't add values to it without updating the checks in
* channelpadding_decide_to_pad_channel().
*/
typedef enum {
CHANNEL_USED_NOT_USED_FOR_FULL_CIRCS = 0,
CHANNEL_USED_FOR_FULL_CIRCS,
CHANNEL_USED_FOR_USER_TRAFFIC,
} channel_usage_info_t;
/** Possible rules for generating circuit IDs on an OR connection. */
typedef enum {
CIRC_ID_TYPE_LOWER=0, /**< Pick from 0..1<<15-1. */
CIRC_ID_TYPE_HIGHER=1, /**< Pick from 1<<15..1<<16-1. */
/** The other side of a connection is an OP: never create circuits to it,
* and let it use any circuit ID it wants. */
CIRC_ID_TYPE_NEITHER=2
} circ_id_type_t;
#define circ_id_type_bitfield_t ENUM_BF(circ_id_type_t)
/* channel states for channel_t */
typedef enum {
/**
* Closed state - channel is inactive
*
* Permitted transitions from:
* - CHANNEL_STATE_CLOSING
* Permitted transitions to:
* - CHANNEL_STATE_OPENING
*/
CHANNEL_STATE_CLOSED = 0,
/**
* Opening state - channel is trying to connect
*
* Permitted transitions from:
* - CHANNEL_STATE_CLOSED
* Permitted transitions to:
* - CHANNEL_STATE_CLOSING
* - CHANNEL_STATE_ERROR
* - CHANNEL_STATE_OPEN
*/
CHANNEL_STATE_OPENING,
/**
* Open state - channel is active and ready for use
*
* Permitted transitions from:
* - CHANNEL_STATE_MAINT
* - CHANNEL_STATE_OPENING
* Permitted transitions to:
* - CHANNEL_STATE_CLOSING
* - CHANNEL_STATE_ERROR
* - CHANNEL_STATE_MAINT
*/
CHANNEL_STATE_OPEN,
/**
* Maintenance state - channel is temporarily offline for subclass specific
* maintenance activities such as TLS renegotiation.
*
* Permitted transitions from:
* - CHANNEL_STATE_OPEN
* Permitted transitions to:
* - CHANNEL_STATE_CLOSING
* - CHANNEL_STATE_ERROR
* - CHANNEL_STATE_OPEN
*/
CHANNEL_STATE_MAINT,
/**
* Closing state - channel is shutting down
*
* Permitted transitions from:
* - CHANNEL_STATE_MAINT
* - CHANNEL_STATE_OPEN
* Permitted transitions to:
* - CHANNEL_STATE_CLOSED,
* - CHANNEL_STATE_ERROR
*/
CHANNEL_STATE_CLOSING,
/**
* Error state - channel has experienced a permanent error
*
* Permitted transitions from:
* - CHANNEL_STATE_CLOSING
* - CHANNEL_STATE_MAINT
* - CHANNEL_STATE_OPENING
* - CHANNEL_STATE_OPEN
* Permitted transitions to:
* - None
*/
CHANNEL_STATE_ERROR,
/**
* Placeholder for maximum state value
*/
CHANNEL_STATE_LAST
} channel_state_t;
/* channel listener states for channel_listener_t */
typedef enum {
/**
* Closed state - channel listener is inactive
*
* Permitted transitions from:
* - CHANNEL_LISTENER_STATE_CLOSING
* Permitted transitions to:
* - CHANNEL_LISTENER_STATE_LISTENING
*/
CHANNEL_LISTENER_STATE_CLOSED = 0,
/**
* Listening state - channel listener is listening for incoming
* connections
*
* Permitted transitions from:
* - CHANNEL_LISTENER_STATE_CLOSED
* Permitted transitions to:
* - CHANNEL_LISTENER_STATE_CLOSING
* - CHANNEL_LISTENER_STATE_ERROR
*/
CHANNEL_LISTENER_STATE_LISTENING,
/**
* Closing state - channel listener is shutting down
*
* Permitted transitions from:
* - CHANNEL_LISTENER_STATE_LISTENING
* Permitted transitions to:
* - CHANNEL_LISTENER_STATE_CLOSED,
* - CHANNEL_LISTENER_STATE_ERROR
*/
CHANNEL_LISTENER_STATE_CLOSING,
/**
* Error state - channel listener has experienced a permanent error
*
* Permitted transitions from:
* - CHANNEL_STATE_CLOSING
* - CHANNEL_STATE_LISTENING
* Permitted transitions to:
* - None
*/
CHANNEL_LISTENER_STATE_ERROR,
/**
* Placeholder for maximum state value
*/
CHANNEL_LISTENER_STATE_LAST
} channel_listener_state_t;
/**
* Channel struct; see the channel_t typedef in or.h. A channel is an
* abstract interface for the OR-to-OR connection, similar to connection_or_t,
* but without the strong coupling to the underlying TLS implementation. They
* are constructed by calling a protocol-specific function to open a channel
* to a particular node, and once constructed support the abstract operations
* defined below.
*/
struct channel_t {
/** Magic number for type-checking cast macros */
uint32_t magic;
/** List entry for hashtable for global-identifier lookup. */
HT_ENTRY(channel_t) gidmap_node;
/** Handle entry for handle-based lookup */
HANDLE_ENTRY(channel, channel_t);
/** Current channel state */
channel_state_t state;
/** Globally unique ID number for a channel over the lifetime of a Tor
* process. This may not be 0.
*/
uint64_t global_identifier;
/** Should we expect to see this channel in the channel lists? */
unsigned char registered:1;
/** has this channel ever been open? */
unsigned int has_been_open:1;
/**
* This field indicates if the other side has enabled or disabled
* padding via either the link protocol version or
* channelpadding_negotiate cells.
*
* Clients can override this with ConnectionPadding in torrc to
* disable or force padding to relays, but relays cannot override the
* client's request.
*/
unsigned int padding_enabled:1;
/** Cached value of our decision to pad (to avoid expensive
* checks during critical path statistics counting). */
unsigned int currently_padding:1;
/** Is there a pending netflow padding callback? */
unsigned int pending_padding_callback:1;
/** Is our peer likely to consider this channel canonical? */
unsigned int is_canonical_to_peer:1;
/** Has this channel ever been used for non-directory traffic?
* Used to decide what channels to pad, and when. */
channel_usage_info_t channel_usage;
/** When should we send a cell for netflow padding? 0 means no padding is
* scheduled. */
monotime_coarse_t next_padding_time;
/** The callback pointer for the padding callbacks */
struct tor_timer_t *padding_timer;
/** The handle to this channel (to free on canceled timers) */
struct channel_handle_t *timer_handle;
/** If not UNSPEC, the address that the peer says we have. */
tor_addr_t addr_according_to_peer;
/**
* These two fields specify the minimum and maximum negotiated timeout
* values for inactivity (send or receive) before we decide to pad a
* channel. These fields can be set either via a PADDING_NEGOTIATE cell,
* or the torrc option ReducedConnectionPadding. The consensus parameters
* nf_ito_low and nf_ito_high are used to ensure that padding can only be
* negotiated to be less frequent than what is specified in the consensus.
* (This is done to prevent wingnut clients from requesting excessive
* padding).
*
* The actual timeout value is randomly chosen between these two values
* as per the table in channelpadding_get_netflow_inactive_timeout_ms(),
* after ensuring that these values do not specify lower timeouts than
* the consensus parameters.
*
* If these are 0, we have not negotiated or specified custom padding
* times, and instead use consensus defaults. */
uint16_t padding_timeout_low_ms;
uint16_t padding_timeout_high_ms;
/** Why did we close?
*/
enum {
CHANNEL_NOT_CLOSING = 0,
CHANNEL_CLOSE_REQUESTED,
CHANNEL_CLOSE_FROM_BELOW,
CHANNEL_CLOSE_FOR_ERROR
} reason_for_closing;
/** State variable for use by the scheduler */
enum {
/**
* The channel is not open, or it has a full output buffer but no queued
* cells.
*/
SCHED_CHAN_IDLE = 0,
/**
* The channel has space on its output buffer to write, but no queued
* cells.
*/
SCHED_CHAN_WAITING_FOR_CELLS,
/**
* The scheduler has queued cells but no output buffer space to write.
*/
SCHED_CHAN_WAITING_TO_WRITE,
/**
* The scheduler has both queued cells and output buffer space, and is
* eligible for the scheduler loop.
*/
SCHED_CHAN_PENDING
} scheduler_state;
/** Heap index for use by the scheduler */
int sched_heap_idx;
/** Timestamps for both cell channels and listeners */
time_t timestamp_created; /* Channel created */
time_t timestamp_active; /* Any activity */
/**
* This is a monotonic timestamp that marks when we
* believe the channel has actually sent or received data to/from
* the wire. Right now, it is used to determine when we should send
* a padding cell for channelpadding.
*
* XXX: Are we setting timestamp_xfer_ms in the right places to
* accurately reflect actual network data transfer? Or might this be
* very wrong wrt when bytes actually go on the wire?
*/
monotime_coarse_t timestamp_xfer;
/* Methods implemented by the lower layer */
/** Free a channel */
void (*free_fn)(channel_t *);
/** Close an open channel */
void (*close)(channel_t *);
/** Describe the transport subclass for this channel */
const char * (*describe_transport)(channel_t *);
/** Optional method to dump transport-specific statistics on the channel */
void (*dumpstats)(channel_t *, int);
/** Registered handlers for incoming cells */
channel_cell_handler_fn_ptr cell_handler;
/* Methods implemented by the lower layer */
/**
* Ask the lower layer for an estimate of the average overhead for
* transmissions on this channel.
*/
double (*get_overhead_estimate)(channel_t *);
/*
* Ask the underlying transport what the remote endpoint address is, in a
* tor_addr_t. Write the address out to the provided tor_addr_t *, and
* return 1 if successful or 0 if no address available.
*/
int (*get_remote_addr)(const channel_t *, tor_addr_t *);
int (*get_transport_name)(channel_t *chan, char **transport_out);
/**
* Get a human-readable text description of the remote endpoint, for
* logging.
*/
const char * (*describe_peer)(const channel_t *);
/** Check if the lower layer has queued writes */
int (*has_queued_writes)(channel_t *);
/**
* Ask the lower layer if this is 'canonical', for a transport-specific
* definition of canonical.
*/
int (*is_canonical)(channel_t *);
/** Check if this channel matches a specified extend_info_t */
int (*matches_extend_info)(channel_t *, extend_info_t *);
/** Check if this channel matches a target address when extending */
int (*matches_target)(channel_t *, const tor_addr_t *);
/* Ask the lower layer how many bytes it has queued but not yet sent */
size_t (*num_bytes_queued)(channel_t *);
/* Ask the lower layer how many cells can be written */
int (*num_cells_writeable)(channel_t *);
/* Write a cell to an open channel */
int (*write_cell)(channel_t *, cell_t *);
/** Write a packed cell to an open channel */
int (*write_packed_cell)(channel_t *, packed_cell_t *);
/** Write a variable-length cell to an open channel */
int (*write_var_cell)(channel_t *, var_cell_t *);
/**
* Hash of the public RSA key for the other side's RSA identity key -- or
* zeroes if we don't have an RSA identity in mind for the other side, and
* it hasn't shown us one.
*
* Note that this is the RSA identity that we hope the other side has -- not
* necessarily its true identity. Don't believe this identity unless
* authentication has happened.
*/
char identity_digest[DIGEST_LEN];
/**
* Ed25519 key for the other side of this channel -- or zeroes if we don't
* have an Ed25519 identity in mind for the other side, and it hasn't shown
* us one.
*
* Note that this is the identity that we hope the other side has -- not
* necessarily its true identity. Don't believe this identity unless
* authentication has happened.
*/
struct ed25519_public_key_t ed25519_identity;
/**
* Linked list of channels with the same RSA identity digest, for use with
* the digest->channel map
*/
TOR_LIST_ENTRY(channel_t) next_with_same_id;
/** Circuit mux for circuits sending on this channel */
circuitmux_t *cmux;
/** Circuit ID generation stuff for use by circuitbuild.c */
/**
* When we send CREATE cells along this connection, which half of the
* space should we use?
*/
circ_id_type_bitfield_t circ_id_type:2;
/* DOCDOC */
unsigned wide_circ_ids:1;
/** For how many circuits are we n_chan? What about p_chan? */
unsigned int num_n_circuits, num_p_circuits;
/**
* True iff this channel shouldn't get any new circs attached to it,
* because the connection is too old, or because there's a better one.
* More generally, this flag is used to note an unhealthy connection;
* for example, if a bad connection fails we shouldn't assume that the
* router itself has a problem.
*/
unsigned int is_bad_for_new_circs:1;
/** True iff we have decided that the other end of this connection
* is a client or bridge relay. Connections with this flag set should never
* be used to satisfy an EXTEND request. */
unsigned int is_client:1;
/** Set if the channel was initiated remotely (came from a listener) */
unsigned int is_incoming:1;
/** Set by lower layer if this is local; i.e., everything it communicates
* with for this channel returns true for is_local_addr(). This is used
* to decide whether to declare reachability when we receive something on
* this channel in circuitbuild.c
*/
unsigned int is_local:1;
/** Have we logged a warning about circID exhaustion on this channel?
* If so, when? */
ratelim_t last_warned_circ_ids_exhausted;
/** Channel timestamps for cell channels */
time_t timestamp_client; /*(< Client used this, according to relay.c */
time_t timestamp_recv; /**< Cell received from lower layer */
time_t timestamp_xmit; /**< Cell sent to lower layer */
/** Timestamp for run_connection_housekeeping(). We update this once a
* second when we run housekeeping and find a circuit on this channel, and
* whenever we add a circuit to the channel. */
time_t timestamp_last_had_circuits;
/** Unique ID for measuring direct network status requests;vtunneled ones
* come over a circuit_t, which has a dirreq_id field as well, but is a
* distinct namespace. */
uint64_t dirreq_id;
/** Channel counters for cells and bytes we have received. */
uint64_t n_cells_recved, n_bytes_recved;
/** Channel counters for cells and bytes we have sent. */
uint64_t n_cells_xmitted, n_bytes_xmitted;
};
struct channel_listener_t {
/** Current channel listener state */
channel_listener_state_t state;
/** Globally unique ID number for a channel over the lifetime of a Tor
* process.
*/
uint64_t global_identifier;
/** Should we expect to see this channel in the channel lists? */
unsigned char registered:1;
/** Why did we close?
*/
enum {
CHANNEL_LISTENER_NOT_CLOSING = 0,
CHANNEL_LISTENER_CLOSE_REQUESTED,
CHANNEL_LISTENER_CLOSE_FROM_BELOW,
CHANNEL_LISTENER_CLOSE_FOR_ERROR
} reason_for_closing;
/** Timestamps for both cell channels and listeners */
time_t timestamp_created; /* Channel created */
time_t timestamp_active; /* Any activity */
/* Methods implemented by the lower layer */
/** Free a channel */
void (*free_fn)(channel_listener_t *);
/** Close an open channel */
void (*close)(channel_listener_t *);
/** Describe the transport subclass for this channel */
const char * (*describe_transport)(channel_listener_t *);
/** Optional method to dump transport-specific statistics on the channel */
void (*dumpstats)(channel_listener_t *, int);
/** Registered listen handler to call on incoming connection */
channel_listener_fn_ptr listener;
/** List of pending incoming connections */
smartlist_t *incoming_list;
/** Timestamps for listeners */
time_t timestamp_accepted;
/** Counters for listeners */
uint64_t n_accepted;
};
/* Channel state manipulations */
int channel_state_is_valid(channel_state_t state);
int channel_listener_state_is_valid(channel_listener_state_t state);
int channel_state_can_transition(channel_state_t from, channel_state_t to);
int channel_listener_state_can_transition(channel_listener_state_t from,
channel_listener_state_t to);
const char * channel_state_to_string(channel_state_t state);
const char *
channel_listener_state_to_string(channel_listener_state_t state);
/* Abstract channel operations */
void channel_mark_for_close(channel_t *chan);
int channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
void channel_listener_mark_for_close(channel_listener_t *chan_l);
void channel_mark_as_used_for_origin_circuit(channel_t *chan);
/* Channel callback registrations */
/* Listener callback */
void channel_listener_set_listener_fn(channel_listener_t *chan,
channel_listener_fn_ptr listener);
/* Incoming cell callbacks */
channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan);
void channel_set_cell_handlers(channel_t *chan,
channel_cell_handler_fn_ptr cell_handler);
/* Clean up closed channels and channel listeners periodically; these are
* called from run_scheduled_events() in main.c.
*/
void channel_run_cleanup(void);
void channel_listener_run_cleanup(void);
/* Close all channels and deallocate everything */
void channel_free_all(void);
/* Dump some statistics in the log */
void channel_dumpstats(int severity);
void channel_listener_dumpstats(int severity);
#ifdef CHANNEL_OBJECT_PRIVATE
#ifdef CHANNEL_FILE_PRIVATE
STATIC void channel_add_to_digest_map(channel_t *chan);
STATIC bool channel_matches_target_addr_for_extend(
channel_t *chan,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr);
#endif /* defined(CHANNEL_FILE_PRIVATE) */
/* Channel operations for subclasses and internal use only */
/* Initialize a newly allocated channel - do this first in subclass
* constructors.
*/
void channel_init(channel_t *chan);
void channel_init_listener(channel_listener_t *chan);
/* Channel registration/unregistration */
void channel_register(channel_t *chan);
void channel_unregister(channel_t *chan);
/* Channel listener registration/unregistration */
void channel_listener_register(channel_listener_t *chan_l);
void channel_listener_unregister(channel_listener_t *chan_l);
/* Close from below */
void channel_close_from_lower_layer(channel_t *chan);
void channel_close_for_error(channel_t *chan);
void channel_closed(channel_t *chan);
/* Free a channel */
void channel_free_(channel_t *chan);
#define channel_free(chan) FREE_AND_NULL(channel_t, channel_free_, (chan))
void channel_listener_free_(channel_listener_t *chan_l);
#define channel_listener_free(chan_l) \
FREE_AND_NULL(channel_listener_t, channel_listener_free_, (chan_l))
/* State/metadata setters */
void channel_change_state(channel_t *chan, channel_state_t to_state);
void channel_change_state_open(channel_t *chan);
void channel_clear_identity_digest(channel_t *chan);
void channel_clear_remote_end(channel_t *chan);
void channel_mark_local(channel_t *chan);
void channel_mark_incoming(channel_t *chan);
void channel_mark_outgoing(channel_t *chan);
void channel_mark_remote(channel_t *chan);
void channel_set_identity_digest(channel_t *chan,
const char *identity_digest,
const struct ed25519_public_key_t *ed_identity);
void channel_listener_change_state(channel_listener_t *chan_l,
channel_listener_state_t to_state);
/* Timestamp updates */
void channel_timestamp_created(channel_t *chan);
void channel_timestamp_active(channel_t *chan);
void channel_timestamp_recv(channel_t *chan);
void channel_timestamp_xmit(channel_t *chan);
void channel_listener_timestamp_created(channel_listener_t *chan_l);
void channel_listener_timestamp_active(channel_listener_t *chan_l);
void channel_listener_timestamp_accepted(channel_listener_t *chan_l);
/* Incoming channel handling */
void channel_listener_process_incoming(channel_listener_t *listener);
void channel_listener_queue_incoming(channel_listener_t *listener,
channel_t *incoming);
/* Incoming cell handling */
void channel_process_cell(channel_t *chan, cell_t *cell);
/* Request from lower layer for more cells if available */
MOCK_DECL(ssize_t, channel_flush_some_cells,
(channel_t *chan, ssize_t num_cells));
/* Query if data available on this channel */
MOCK_DECL(int, channel_more_to_flush, (channel_t *chan));
/* Notify flushed outgoing for dirreq handling */
void channel_notify_flushed(channel_t *chan);
/* Handle stuff we need to do on open like notifying circuits */
void channel_do_open_actions(channel_t *chan);
#endif /* defined(CHANNEL_OBJECT_PRIVATE) */
/* Helper functions to perform operations on channels */
int channel_send_destroy(circid_t circ_id, channel_t *chan,
int reason);
/*
* Outside abstract interfaces that should eventually get turned into
* something transport/address format independent.
*/
channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id);
MOCK_DECL(channel_t *, channel_get_for_extend,(
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr,
bool for_origin_circ,
const char **msg_out,
int *launch_out));
/* Ask which of two channels is better for circuit-extension purposes */
int channel_is_better(channel_t *a, channel_t *b);
/** Channel lookups
*/
channel_t * channel_find_by_global_id(uint64_t global_identifier);
channel_t * channel_find_by_remote_identity(const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id);
/** For things returned by channel_find_by_remote_digest(), walk the list.
* The RSA key will match for all returned elements; the Ed25519 key might not.
*/
channel_t * channel_next_with_rsa_identity(channel_t *chan);
/*
* Helper macros to lookup state of given channel.
*/
#define CHANNEL_IS_CLOSED(chan) (channel_is_in_state((chan), \
CHANNEL_STATE_CLOSED))
#define CHANNEL_IS_OPENING(chan) (channel_is_in_state((chan), \
CHANNEL_STATE_OPENING))
#define CHANNEL_IS_OPEN(chan) (channel_is_in_state((chan), \
CHANNEL_STATE_OPEN))
#define CHANNEL_IS_MAINT(chan) (channel_is_in_state((chan), \
CHANNEL_STATE_MAINT))
#define CHANNEL_IS_CLOSING(chan) (channel_is_in_state((chan), \
CHANNEL_STATE_CLOSING))
#define CHANNEL_IS_ERROR(chan) (channel_is_in_state((chan), \
CHANNEL_STATE_ERROR))
#define CHANNEL_FINISHED(chan) (CHANNEL_IS_CLOSED(chan) || \
CHANNEL_IS_ERROR(chan))
#define CHANNEL_CONDEMNED(chan) (CHANNEL_IS_CLOSING(chan) || \
CHANNEL_FINISHED(chan))
#define CHANNEL_CAN_HANDLE_CELLS(chan) (CHANNEL_IS_OPENING(chan) || \
CHANNEL_IS_OPEN(chan) || \
CHANNEL_IS_MAINT(chan))
static inline int
channel_is_in_state(channel_t *chan, channel_state_t state)
{
return chan->state == state;
}
/*
* Metadata queries/updates
*/
const char * channel_describe_transport(channel_t *chan);
MOCK_DECL(void, channel_dump_statistics, (channel_t *chan, int severity));
void channel_dump_transport_statistics(channel_t *chan, int severity);
MOCK_DECL(int, channel_get_addr_if_possible, (const channel_t *chan,
tor_addr_t *addr_out));
MOCK_DECL(const char *, channel_describe_peer,(channel_t *chan));
int channel_has_queued_writes(channel_t *chan);
int channel_is_bad_for_new_circs(channel_t *chan);
void channel_mark_bad_for_new_circs(channel_t *chan);
int channel_is_canonical(channel_t *chan);
int channel_is_client(const channel_t *chan);
int channel_is_local(channel_t *chan);
int channel_is_incoming(channel_t *chan);
int channel_is_outgoing(channel_t *chan);
void channel_mark_client(channel_t *chan);
void channel_clear_client(channel_t *chan);
int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
int channel_remote_identity_matches(const channel_t *chan,
const char *rsa_id_digest,
const ed25519_public_key_t *ed_id);
unsigned int channel_num_circuits(channel_t *chan);
MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
crypto_pk_t *identity_rcvd,
int consider_identity));
void channel_timestamp_client(channel_t *chan);
const char * channel_listener_describe_transport(channel_listener_t *chan_l);
void channel_listener_dump_statistics(channel_listener_t *chan_l,
int severity);
void channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
int severity);
void channel_check_for_duplicates(void);
void channel_update_bad_for_new_circs(const char *digest, int force);
/* Flow control queries */
int channel_num_cells_writeable(channel_t *chan);
/* Timestamp queries */
time_t channel_when_created(channel_t *chan);
time_t channel_when_last_client(channel_t *chan);
time_t channel_when_last_xmit(channel_t *chan);
/* Counter queries */
int packed_cell_is_destroy(channel_t *chan,
const packed_cell_t *packed_cell,
circid_t *circid_out);
/* Declare the handle helpers */
HANDLE_DECL(channel, channel_t,)
#define channel_handle_free(h) \
FREE_AND_NULL(channel_handle_t, channel_handle_free_, (h))
#undef tor_timer_t
#endif /* !defined(TOR_CHANNEL_H) */
@@ -0,0 +1,42 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitbuild.h
* \brief Header file for circuitbuild.c.
**/
#ifndef TOR_CHANNELPADDING_H
#define TOR_CHANNELPADDING_H
#include "trunnel/channelpadding_negotiation.h"
#define CHANNELPADDING_SOS_PARAM "nf_pad_single_onion"
#define CHANNELPADDING_SOS_DEFAULT 1
typedef enum {
CHANNELPADDING_WONTPAD,
CHANNELPADDING_PADLATER,
CHANNELPADDING_PADDING_SCHEDULED,
CHANNELPADDING_PADDING_ALREADY_SCHEDULED,
CHANNELPADDING_PADDING_SENT,
} channelpadding_decision_t;
channelpadding_decision_t channelpadding_decide_to_pad_channel(channel_t
*chan);
int channelpadding_update_padding_for_channel(channel_t *,
const channelpadding_negotiate_t
*chan);
void channelpadding_disable_padding_on_channel(channel_t *chan);
void channelpadding_reduce_padding_on_channel(channel_t *chan);
int channelpadding_send_enable_command(channel_t *chan, uint16_t low_timeout,
uint16_t high_timeout);
int channelpadding_get_circuits_available_timeout(void);
unsigned int channelpadding_get_channel_idle_timeout(const channel_t *, int);
void channelpadding_new_consensus_params(const networkstatus_t *ns);
#endif /* !defined(TOR_CHANNELPADDING_H) */
@@ -0,0 +1,82 @@
/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file channeltls.h
* \brief Header file for channeltls.c
**/
#ifndef TOR_CHANNELTLS_H
#define TOR_CHANNELTLS_H
#include "core/or/or.h"
#include "core/or/channel.h"
struct ed25519_public_key_t;
struct curve25519_public_key_t;
#define TLS_PER_CELL_OVERHEAD 29
#define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c)))
#define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c)))
#define CONST_BASE_CHAN_TO_TLS(c) (channel_tls_from_base_const((c)))
#define CONST_TLS_CHAN_TO_BASE(c) (channel_tls_to_base_const((c)))
#define TLS_CHAN_MAGIC 0x8a192427U
#ifdef CHANNEL_OBJECT_PRIVATE
struct channel_tls_t {
/* Base channel_t struct */
channel_t base_;
/* or_connection_t pointer */
or_connection_t *conn;
};
#endif /* defined(CHANNEL_OBJECT_PRIVATE) */
channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port,
const char *id_digest,
const struct ed25519_public_key_t *ed_id);
channel_listener_t * channel_tls_get_listener(void);
channel_listener_t * channel_tls_start_listener(void);
channel_t * channel_tls_handle_incoming(or_connection_t *orconn);
/* Casts */
channel_t * channel_tls_to_base(channel_tls_t *tlschan);
channel_tls_t * channel_tls_from_base(channel_t *chan);
const channel_t * channel_tls_to_base_const(const channel_tls_t *tlschan);
const channel_tls_t * channel_tls_from_base_const(const channel_t *chan);
/* Things for connection_or.c to call back into */
void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
or_connection_t *conn,
uint8_t state);
void channel_tls_handle_var_cell(var_cell_t *var_cell,
or_connection_t *conn);
void channel_tls_update_marks(or_connection_t *conn);
/* Cleanup at shutdown */
void channel_tls_free_all(void);
extern uint64_t stats_n_authorize_cells_processed;
extern uint64_t stats_n_authenticate_cells_processed;
extern uint64_t stats_n_versions_cells_processed;
extern uint64_t stats_n_netinfo_cells_processed;
extern uint64_t stats_n_vpadding_cells_processed;
extern uint64_t stats_n_certs_cells_processed;
extern uint64_t stats_n_auth_challenge_cells_processed;
#ifdef CHANNELTLS_PRIVATE
STATIC void channel_tls_process_certs_cell(var_cell_t *cell,
channel_tls_t *tlschan);
STATIC void channel_tls_process_auth_challenge_cell(var_cell_t *cell,
channel_tls_t *tlschan);
STATIC void channel_tls_common_init(channel_tls_t *tlschan);
STATIC void channel_tls_process_authenticate_cell(var_cell_t *cell,
channel_tls_t *tlschan);
#endif /* defined(CHANNELTLS_PRIVATE) */
#endif /* !defined(TOR_CHANNELTLS_H) */
@@ -0,0 +1,274 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file circuit_st.h
* @brief Base circuit structure.
**/
#ifndef CIRCUIT_ST_H
#define CIRCUIT_ST_H
#include "core/or/or.h"
#include "lib/container/handles.h"
#include "core/or/cell_queue_st.h"
#include "ext/ht.h"
struct hs_token_t;
struct circpad_machine_spec_t;
struct circpad_machine_runtime_t;
struct congestion_control_t;
/** Number of padding state machines on a circuit. */
#define CIRCPAD_MAX_MACHINES (2)
/** "magic" value for an origin_circuit_t */
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
/** "magic" value for an or_circuit_t */
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
/** "magic" value for a circuit that would have been freed by circuit_free,
* but which we're keeping around until a cpuworker reply arrives. See
* circuit_free() for more documentation. */
#define DEAD_CIRCUIT_MAGIC 0xdeadc14c
/**
* A circuit is a path over the onion routing
* network. Applications can connect to one end of the circuit, and can
* create exit connections at the other end of the circuit. AP and exit
* connections have only one circuit associated with them (and thus these
* connection types are closed when the circuit is closed), whereas
* OR connections multiplex many circuits at once, and stay standing even
* when there are no circuits running over them.
*
* A circuit_t structure can fill one of two roles. First, a or_circuit_t
* links two connections together: either an edge connection and an OR
* connection, or two OR connections. (When joined to an OR connection, a
* circuit_t affects only cells sent to a particular circID on that
* connection. When joined to an edge connection, a circuit_t affects all
* data.)
* Second, an origin_circuit_t holds the cipher keys and state for sending data
* along a given circuit. At the OP, it has a sequence of ciphers, each
* of which is shared with a single OR along the circuit. Separate
* ciphers are used for data going "forward" (away from the OP) and
* "backward" (towards the OP). At the OR, a circuit has only two stream
* ciphers: one for data going forward, and one for data going backward.
*/
struct circuit_t {
uint32_t magic; /**< For memory and type debugging: must equal
* ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
/** Handle entry for handle-based lookup */
HANDLE_ENTRY(circuit, circuit_t);
/** The channel that is next in this circuit. */
channel_t *n_chan;
/**
* The circuit_id used in the next (forward) hop of this circuit;
* this is unique to n_chan, but this ordered pair is globally
* unique:
*
* (n_chan->global_identifier, n_circ_id)
*/
circid_t n_circ_id;
/** Queue of cells waiting to be transmitted on n_chan */
cell_queue_t n_chan_cells;
/**
* The hop to which we want to extend this circuit. Should be NULL if
* the circuit has attached to a channel.
*/
extend_info_t *n_hop;
/** True iff we are waiting for n_chan_cells to become less full before
* allowing any more cells on this circuit. (Origin circuit only.) */
unsigned int circuit_blocked_on_n_chan : 1;
/** True iff we are waiting for p_chan_cells to become less full before
* allowing any more cells on this circuit. (OR circuit only.) */
unsigned int circuit_blocked_on_p_chan : 1;
/** True iff we have queued a delete backwards on this circuit, but not put
* it on the output buffer. */
unsigned int p_delete_pending : 1;
/** True iff we have queued a delete forwards on this circuit, but not put
* it on the output buffer. */
unsigned int n_delete_pending : 1;
/** True iff this circuit has received a DESTROY cell in either direction */
unsigned int received_destroy : 1;
/** True iff we have sent a sufficiently random data cell since last
* we reset send_randomness_after_n_cells. */
unsigned int have_sent_sufficiently_random_cell : 1;
uint8_t state; /**< Current status of this circuit. */
uint8_t purpose; /**< Why are we creating this circuit? */
/** How many relay data cells can we package (read from edge streams)
* on this circuit before we receive a circuit-level sendme cell asking
* for more? */
int package_window;
/** How many relay data cells will we deliver (write to edge streams)
* on this circuit? When deliver_window gets low, we send some
* circuit-level sendme cells to indicate that we're willing to accept
* more. */
int deliver_window;
/**
* How many cells do we have until we need to send one that contains
* sufficient randomness? Used to ensure that authenticated SENDME cells
* will reflect some unpredictable information.
**/
uint16_t send_randomness_after_n_cells;
/** FIFO containing the digest of the cells that are just before a SENDME is
* sent by the client. It is done at the last cell before our package_window
* goes down to 0 which is when we expect a SENDME.
*
* Our current circuit package window is capped to 1000
* (CIRCWINDOW_START_MAX) which is also the start value. The increment is
* set to 100 (CIRCWINDOW_INCREMENT) which means we don't allow more than
* 1000/100 = 10 outstanding SENDME cells worth of data. Meaning that this
* list can not contain more than 10 digests of DIGEST_LEN bytes (20).
*
* At position i in the list, the digest corresponds to the
* (CIRCWINDOW_INCREMENT * i)-nth cell received since we expect a SENDME to
* be received containing that cell digest.
*
* For example, position 2 (starting at 0) means that we've received 300
* cells so the 300th cell digest is kept at index 2.
*
* At maximum, this list contains 200 bytes plus the smartlist overhead. */
smartlist_t *sendme_last_digests;
/** Temporary field used during circuits_handle_oom. */
uint32_t age_tmp;
/** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */
struct create_cell_t *n_chan_create_cell;
/** When did circuit construction actually begin (ie send the
* CREATE cell or begin cannibalization).
*
* Note: This timer will get reset if we decide to cannibalize
* a circuit. It may also get reset during certain phases of hidden
* service circuit use.
*
* We keep this timestamp with a higher resolution than most so that the
* circuit-build-time tracking code can get millisecond resolution.
*/
struct timeval timestamp_began;
/** This timestamp marks when the init_circuit_base constructor ran. */
struct timeval timestamp_created;
/** When the circuit was first used, or 0 if the circuit is clean.
*
* XXXX Note that some code will artificially adjust this value backward
* in time in order to indicate that a circuit shouldn't be used for new
* streams, but that it can stay alive as long as it has streams on it.
* That's a kludge we should fix.
*
* XXX The CBT code uses this field to record when HS-related
* circuits entered certain states. This usage probably won't
* interfere with this field's primary purpose, but we should
* document it more thoroughly to make sure of that.
*
* XXX The SocksPort option KeepaliveIsolateSOCKSAuth will artificially
* adjust this value forward each time a suitable stream is attached to an
* already constructed circuit, potentially keeping the circuit alive
* indefinitely.
*/
time_t timestamp_dirty;
uint16_t marked_for_close; /**< Should we close this circuit at the end of
* the main loop? (If true, holds the line number
* where this circuit was marked.) */
const char *marked_for_close_file; /**< For debugging: in which file was this
* circuit marked for close? */
/** For what reason (See END_CIRC_REASON...) is this circuit being closed?
* This field is set in circuit_mark_for_close and used later in
* circuit_about_to_free. */
int marked_for_close_reason;
/** As marked_for_close_reason, but reflects the underlying reason for
* closing this circuit.
*/
int marked_for_close_orig_reason;
/** Unique ID for measuring tunneled network status requests. */
uint64_t dirreq_id;
/** Index in smartlist of all circuits (global_circuitlist). */
int global_circuitlist_idx;
/** Various statistics about cells being added to or removed from this
* circuit's queues; used only if CELL_STATS events are enabled and
* cleared after being sent to control port. */
smartlist_t *testing_cell_stats;
/** If set, points to an HS token that this circuit might be carrying.
* Used by the HS circuitmap. */
struct hs_token_t *hs_token;
/** Hashtable node: used to look up the circuit by its HS token using the HS
circuitmap. */
HT_ENTRY(circuit_t) hs_circuitmap_node;
/** Adaptive Padding state machines: these are immutable. The state machines
* that come from the consensus are saved to a global structure, to avoid
* per-circuit allocations. This merely points to the global copy in
* origin_padding_machines or relay_padding_machines that should never
* change or get deallocated.
*
* Each element of this array corresponds to a different padding machine,
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
const struct circpad_machine_spec_t *padding_machine[CIRCPAD_MAX_MACHINES];
/** Adaptive Padding machine runtime info for above machines. This is
* the per-circuit mutable information, such as the current state and
* histogram token counts. Some of it is optional (aka NULL).
* If a machine is being shut down, these indexes can be NULL
* without the corresponding padding_machine being NULL, while we
* wait for the other end to respond to our shutdown request.
*
* Each element of this array corresponds to a different padding machine,
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
struct circpad_machine_runtime_t *padding_info[CIRCPAD_MAX_MACHINES];
/** padding_machine_ctr increments each time a new padding machine
* is negotiated. It is used for shutdown conditions, to ensure
* that STOP commands actually correspond to the current machine,
* and not a previous one. */
uint32_t padding_machine_ctr;
/** Congestion control fields */
struct congestion_control_t *ccontrol;
/** Conflux linked circuit information.
*
* If this is non-NULL, the circuit is linked and part of a usable set,
* and for origin_circuit_t subtypes, the circuit purpose is
* CIRCUIT_PURPOSE_CONFLUX_LINKED.
*
* If this is NULL, the circuit could still be part of a pending conflux
* object, in which case the conflux_pending_nonce field is set, and for
* origin_circuit_t subtypes, the purpose is
* CIRCUIT_PURPOSE_CONFLUX_UNLINKED.
*/
struct conflux_t *conflux;
/** If set, this circuit is considered *unlinked* and in the pending pool.
* The nonce value is used to find the other legs. Origin circuits that
* have this set are in the CIRCUIT_PURPOSE_CONFLUX_UNLINKED purpose.
*
* If this is NULL, and conflux object is set, it means this circuit is
* linked and thus part of a usable set. */
uint8_t *conflux_pending_nonce;
};
#endif /* !defined(CIRCUIT_ST_H) */
@@ -0,0 +1,96 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitbuild.h
* \brief Header file for circuitbuild.c.
**/
#ifndef TOR_CIRCUITBUILD_H
#define TOR_CIRCUITBUILD_H
struct ed25519_public_key_t;
struct curve25519_public_key_t;
int route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei);
char *circuit_list_path(origin_circuit_t *circ, int verbose);
char *circuit_list_path_for_controller(origin_circuit_t *circ);
void circuit_log_path(int severity, unsigned int domain,
origin_circuit_t *circ);
origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int flags);
MOCK_DECL(origin_circuit_t *, circuit_establish_circuit_conflux, (
const uint8_t *nonce,
uint8_t purpose,
extend_info_t *exit,
int flags));
struct circuit_guard_state_t *origin_circuit_get_guard_state(
origin_circuit_t *circ);
int circuit_handle_first_hop(origin_circuit_t *circ);
void circuit_n_chan_done(channel_t *chan, int status,
int close_origin_circuits);
int circuit_timeout_want_to_count_circ(const origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
void circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle);
struct created_cell_t;
int circuit_finish_handshake(origin_circuit_t *circ,
const struct created_cell_t *created_cell);
int circuit_truncated(origin_circuit_t *circ, int reason);
MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
int *need_uptime,
int *need_capacity));
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_can_use_tap(const origin_circuit_t *circ);
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
MOCK_DECL(const node_t *,
build_state_get_exit_node,(cpath_build_state_t *state));
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
struct circuit_guard_state_t;
const node_t *choose_good_entry_server(const origin_circuit_t *circ,
uint8_t purpose,
cpath_build_state_t *state,
struct circuit_guard_state_t **guard_state_out);
void circuit_upgrade_circuits_from_guard_wait(void);
MOCK_DECL(channel_t *, channel_connect_for_circuit,(const extend_info_t *ei));
struct create_cell_t;
MOCK_DECL(int,
circuit_deliver_create_cell,(circuit_t *circ,
const struct create_cell_t *create_cell,
int relayed));
int client_circ_negotiation_message(const extend_info_t *ei,
uint8_t **msg_out,
size_t *msg_len_out);
#ifdef CIRCUITBUILD_PRIVATE
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei,
const smartlist_t *nodes);
MOCK_DECL(STATIC int, count_acceptable_nodes, (const smartlist_t *nodes,
int direct));
STATIC int onion_extend_cpath(origin_circuit_t *circ);
STATIC int
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei);
STATIC int cpath_build_state_to_crn_flags(const cpath_build_state_t *state);
STATIC int cpath_build_state_to_crn_ipv6_extend_flag(
const cpath_build_state_t *state,
int cur_len);
#endif /* defined(CIRCUITBUILD_PRIVATE) */
#endif /* !defined(TOR_CIRCUITBUILD_H) */
@@ -0,0 +1,273 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitlist.h
* \brief Header file for circuitlist.c.
**/
#ifndef TOR_CIRCUITLIST_H
#define TOR_CIRCUITLIST_H
#include "lib/container/handles.h"
#include "lib/testsupport/testsupport.h"
#include "feature/hs/hs_ident.h"
#include "core/or/ocirc_event.h"
/** Circuit state: I'm the origin, still haven't done all my handshakes. */
#define CIRCUIT_STATE_BUILDING 0
/** Circuit state: Waiting to process the onionskin. */
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1
/** Circuit state: I'd like to deliver a create, but my n_chan is still
* connecting. */
#define CIRCUIT_STATE_CHAN_WAIT 2
/** Circuit state: the circuit is open but we don't want to actually use it
* until we find out if a better guard will be available.
*/
#define CIRCUIT_STATE_GUARD_WAIT 3
/** Circuit state: onionskin(s) processed, ready to send/receive cells. */
#define CIRCUIT_STATE_OPEN 4
#define CIRCUIT_PURPOSE_MIN_ 1
/* these circuits were initiated elsewhere */
#define CIRCUIT_PURPOSE_OR_MIN_ 1
/** OR-side circuit purpose: normal circuit, at OR. */
#define CIRCUIT_PURPOSE_OR 1
/** OR-side circuit purpose: At OR, from the service, waiting for intro from
* clients. */
#define CIRCUIT_PURPOSE_INTRO_POINT 2
/** OR-side circuit purpose: At OR, from the client, waiting for the service.
*/
#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3
/** OR-side circuit purpose: At OR, both circuits have this purpose. */
#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4
#define CIRCUIT_PURPOSE_OR_MAX_ 4
/* these circuits originate at this node */
/* here's how circ client-side purposes work:
* normal circuits are C_GENERAL.
* circuits that are c_introducing are either on their way to
* becoming open, or they are open and waiting for a
* suitable rendcirc before they send the intro.
* circuits that are c_introduce_ack_wait have sent the intro,
* but haven't gotten a response yet.
* circuits that are c_establish_rend are either on their way
* to becoming open, or they are open and have sent the
* establish_rendezvous cell but haven't received an ack.
* circuits that are c_rend_ready are open and have received a
* rend ack, but haven't heard from the service yet.
* circuits that are c_rend_ready_intro_acked are open, and
* some intro circ has sent its intro and received an ack.
* circuits that are c_rend_joined are open, have heard from
* the service, and are talking to it.
*/
/** Client-side circuit purpose: Normal circuit, with cpath. */
#define CIRCUIT_PURPOSE_C_GENERAL 5
#define CIRCUIT_PURPOSE_C_HS_MIN_ 6
/** Client-side circuit purpose: at the client, connecting to intro point. */
#define CIRCUIT_PURPOSE_C_INTRODUCING 6
/** Client-side circuit purpose: at the client, sent INTRODUCE1 to intro point,
* waiting for ACK/NAK. */
#define CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT 7
/** Client-side circuit purpose: at the client, introduced and acked, closing.
*/
#define CIRCUIT_PURPOSE_C_INTRODUCE_ACKED 8
/** Client-side circuit purpose: at the client, waiting for ack. */
#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 9
/** Client-side circuit purpose: at the client, waiting for the service. */
#define CIRCUIT_PURPOSE_C_REND_READY 10
/** Client-side circuit purpose: at the client, waiting for the service,
* INTRODUCE has been acknowledged. */
#define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED 11
/** Client-side circuit purpose: at the client, rendezvous established. */
#define CIRCUIT_PURPOSE_C_REND_JOINED 12
/** This circuit is used for getting hsdirs */
#define CIRCUIT_PURPOSE_C_HSDIR_GET 13
#define CIRCUIT_PURPOSE_C_HS_MAX_ 13
/** This circuit is used for build time measurement only */
#define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 14
/** This circuit is being held open by circuit padding */
#define CIRCUIT_PURPOSE_C_CIRCUIT_PADDING 15
#define CIRCUIT_PURPOSE_C_MAX_ 15
#define CIRCUIT_PURPOSE_S_HS_MIN_ 16
/** Hidden-service-side circuit purpose: at the service, waiting for
* introductions. */
#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 16
/** Hidden-service-side circuit purpose: at the service, successfully
* established intro. */
#define CIRCUIT_PURPOSE_S_INTRO 17
/** Hidden-service-side circuit purpose: at the service, connecting to rend
* point. */
#define CIRCUIT_PURPOSE_S_CONNECT_REND 18
/** Hidden-service-side circuit purpose: at the service, rendezvous
* established. */
#define CIRCUIT_PURPOSE_S_REND_JOINED 19
/** This circuit is used for uploading hsdirs */
#define CIRCUIT_PURPOSE_S_HSDIR_POST 20
#define CIRCUIT_PURPOSE_S_HS_MAX_ 20
/** A testing circuit; not meant to be used for actual traffic. It is used for
* bandwidth measurement, reachability test and address discovery from an
* authority using the NETINFO cell. */
#define CIRCUIT_PURPOSE_TESTING 21
/** A controller made this circuit and Tor should not cannibalize it or attach
* streams to it without explicitly being told. */
#define CIRCUIT_PURPOSE_CONTROLLER 22
/** This circuit is used for path bias probing only */
#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 23
/** This circuit is used for vanguards/restricted paths.
*
* This type of circuit is *only* created preemptively and never
* on-demand. When an HS operation needs to take place (e.g. connect to an
* intro point), these circuits are then cannibalized and repurposed to the
* actual needed HS purpose. */
#define CIRCUIT_PURPOSE_HS_VANGUARDS 24
/**
* These two purposes are for conflux. The first is for circuits that are
* being built, but not yet linked. The second is for circuits that are
* linked and ready to use for streams. */
#define CIRCUIT_PURPOSE_CONFLUX_UNLINKED 25
#define CIRCUIT_PURPOSE_CONFLUX_LINKED 26
#define CIRCUIT_PURPOSE_MAX_ 26
/** A catch-all for unrecognized purposes. Currently we don't expect
* to make or see any circuits with this purpose. */
#define CIRCUIT_PURPOSE_UNKNOWN 255
/** True iff the circuit purpose <b>p</b> is for a circuit that
* originated at this node. */
#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_)
/** True iff the circuit purpose <b>p</b> is for a circuit that originated
* here to serve as a client. (Hidden services don't count here.) */
#define CIRCUIT_PURPOSE_IS_CLIENT(p) \
((p)> CIRCUIT_PURPOSE_OR_MAX_ && \
(p)<=CIRCUIT_PURPOSE_C_MAX_)
/** True iff the circuit_t <b>c</b> is actually an origin_circuit_t. */
#define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose))
/** True iff the circuit purpose <b>p</b> is for an established rendezvous
* circuit. */
#define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \
((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \
(p) == CIRCUIT_PURPOSE_S_REND_JOINED)
/** True iff the circuit_t c is actually an or_circuit_t */
#define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC)
/** True iff this circuit purpose should count towards the global
* pending rate limit (set by MaxClientCircuitsPending). We count all
* general purpose circuits, as well as the first step of client onion
* service connections (HSDir gets). */
#define CIRCUIT_PURPOSE_COUNTS_TOWARDS_MAXPENDING(p) \
((p) == CIRCUIT_PURPOSE_C_GENERAL || \
(p) == CIRCUIT_PURPOSE_C_HSDIR_GET)
/** Stats. */
extern double cc_stats_circ_close_cwnd_ma;
extern double cc_stats_circ_close_ss_cwnd_ma;
extern uint64_t cc_stats_circs_closed;
/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert
* if the cast is impossible. */
or_circuit_t *TO_OR_CIRCUIT(circuit_t *);
const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *);
/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t.
* Assert if the cast is impossible. */
origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *);
const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT(const circuit_t *);
MOCK_DECL(smartlist_t *, circuit_get_global_list, (void));
smartlist_t *circuit_get_global_origin_circuit_list(void);
int circuit_any_opened_circuits(void);
int circuit_any_opened_circuits_cached(void);
void circuit_cache_opened_circuit_state(int circuits_are_opened);
const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose);
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
const char *circuit_purpose_to_string(uint8_t purpose);
void circuit_dump_by_conn(connection_t *conn, int severity);
void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
channel_t *chan);
void circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
channel_t *chan);
void channel_mark_circid_unusable(channel_t *chan, circid_t id);
void channel_mark_circid_usable(channel_t *chan, circid_t id);
time_t circuit_id_when_marked_unusable_on_channel(circid_t circ_id,
channel_t *chan);
int circuit_event_status(origin_circuit_t *circ, circuit_status_event_t tp,
int reason_code);
void circuit_set_state(circuit_t *circ, uint8_t state);
void circuit_close_all_marked(void);
int32_t circuit_initial_package_window(void);
origin_circuit_t *origin_circuit_new(void);
or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan);
circuit_t *circuit_get_by_circid_channel(circid_t circ_id,
channel_t *chan);
circuit_t *
circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
channel_t *chan);
int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan);
circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
void circuit_unlink_all_from_channel(channel_t *chan, int reason);
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
origin_circuit_t *circuit_get_next_by_purpose(origin_circuit_t *start,
uint8_t purpose);
origin_circuit_t *circuit_get_next_intro_circ(const origin_circuit_t *start,
bool want_client_circ);
origin_circuit_t *circuit_get_next_service_rp_circ(origin_circuit_t *start);
origin_circuit_t *circuit_get_next_service_hsdir_circ(origin_circuit_t *start);
origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
extend_info_t *info, int flags);
void circuit_mark_all_unused_circs(void);
void circuit_mark_all_dirty_circs_as_unusable(void);
void circuit_synchronize_written_or_bandwidth(const circuit_t *c,
circuit_channel_direction_t dir);
MOCK_DECL(void, circuit_mark_for_close_, (circuit_t *circ, int reason,
int line, const char *cfile));
int circuit_get_cpath_len(origin_circuit_t *circ);
int circuit_get_cpath_opened_len(const origin_circuit_t *);
void circuit_clear_cpath(origin_circuit_t *circ);
crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum);
void circuit_get_all_pending_on_channel(smartlist_t *out,
channel_t *chan);
int circuit_count_pending_on_channel(channel_t *chan);
#define circuit_mark_for_close(c, reason) \
circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__)
MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c));
void circuit_free_all(void);
size_t circuits_handle_oom(size_t current_allocation);
void circuit_clear_testing_cell_stats(circuit_t *circ);
void channel_note_destroy_pending(channel_t *chan, circid_t id);
MOCK_DECL(void, channel_note_destroy_not_pending,
(channel_t *chan, circid_t id));
smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void);
bool circuit_is_queue_full(const circuit_t *circ, cell_direction_t direction);
/* Declare the handle helpers */
HANDLE_DECL(circuit, circuit_t, )
#define circuit_handle_free(h) \
FREE_AND_NULL(circuit_handle_t, circuit_handle_free_, (h))
#ifdef CIRCUITLIST_PRIVATE
STATIC void circuit_free_(circuit_t *circ);
#define circuit_free(circ) FREE_AND_NULL(circuit_t, circuit_free_, (circ))
STATIC size_t n_cells_in_circ_queues(const circuit_t *c);
STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now);
STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now);
STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now);
#endif /* defined(CIRCUITLIST_PRIVATE) */
#endif /* !defined(TOR_CIRCUITLIST_H) */
@@ -0,0 +1,218 @@
/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitmux.h
* \brief Header file for circuitmux.c
**/
#ifndef TOR_CIRCUITMUX_H
#define TOR_CIRCUITMUX_H
#include "core/or/or.h"
#include "lib/testsupport/testsupport.h"
typedef struct circuitmux_policy_t circuitmux_policy_t;
typedef struct circuitmux_policy_data_t circuitmux_policy_data_t;
typedef struct circuitmux_policy_circ_data_t circuitmux_policy_circ_data_t;
struct circuitmux_policy_t {
/* Allocate cmux-wide policy-specific data */
circuitmux_policy_data_t * (*alloc_cmux_data)(circuitmux_t *cmux);
/* Free cmux-wide policy-specific data */
void (*free_cmux_data)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data);
/* Allocate circuit policy-specific data for a newly attached circuit */
circuitmux_policy_circ_data_t *
(*alloc_circ_data)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data,
circuit_t *circ,
cell_direction_t direction,
unsigned int cell_count);
/* Free circuit policy-specific data */
void (*free_circ_data)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data,
circuit_t *circ,
circuitmux_policy_circ_data_t *pol_circ_data);
/* Notify that a circuit has become active/inactive */
void (*notify_circ_active)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data,
circuit_t *circ,
circuitmux_policy_circ_data_t *pol_circ_data);
void (*notify_circ_inactive)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data,
circuit_t *circ,
circuitmux_policy_circ_data_t *pol_circ_data);
/* Notify of arriving/transmitted cells on a circuit */
void (*notify_set_n_cells)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data,
circuit_t *circ,
circuitmux_policy_circ_data_t *pol_circ_data,
unsigned int n_cells);
void (*notify_xmit_cells)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data,
circuit_t *circ,
circuitmux_policy_circ_data_t *pol_circ_data,
unsigned int n_cells);
/* Choose a circuit */
circuit_t * (*pick_active_circuit)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data);
/* Optional: channel comparator for use by the scheduler */
int (*cmp_cmux)(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
circuitmux_t *cmux_2, circuitmux_policy_data_t *pol_data_2);
};
/*
* Circuitmux policy implementations can subclass this to store circuitmux-
* wide data; it just has the magic number in the base struct.
*/
struct circuitmux_policy_data_t {
uint32_t magic;
};
/*
* Circuitmux policy implementations can subclass this to store circuit-
* specific data; it just has the magic number in the base struct.
*/
struct circuitmux_policy_circ_data_t {
uint32_t magic;
};
/*
* Upcast #defines for the above types
*/
/**
* Convert a circuitmux_policy_data_t subtype to a circuitmux_policy_data_t.
*/
#define TO_CMUX_POL_DATA(x) (&((x)->base_))
/**
* Convert a circuitmux_policy_circ_data_t subtype to a
* circuitmux_policy_circ_data_t.
*/
#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->base_))
/* Consistency check */
void circuitmux_assert_okay(circuitmux_t *cmux);
/* Create/destroy */
circuitmux_t * circuitmux_alloc(void);
void circuitmux_detach_all_circuits(circuitmux_t *cmux,
smartlist_t *detached_out);
void circuitmux_free_(circuitmux_t *cmux);
#define circuitmux_free(cmux) \
FREE_AND_NULL(circuitmux_t, circuitmux_free_, (cmux))
/* Policy control */
void circuitmux_clear_policy(circuitmux_t *cmux);
MOCK_DECL(const circuitmux_policy_t *,
circuitmux_get_policy, (circuitmux_t *cmux));
void circuitmux_set_policy(circuitmux_t *cmux,
const circuitmux_policy_t *pol);
/* Status inquiries */
cell_direction_t circuitmux_attached_circuit_direction(
circuitmux_t *cmux,
circuit_t *circ);
int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ);
int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ);
unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux,
circuit_t *circ);
MOCK_DECL(unsigned int, circuitmux_num_cells, (circuitmux_t *cmux));
unsigned int circuitmux_num_circuits(circuitmux_t *cmux);
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux);
/* Debugging interface - slow. */
int64_t circuitmux_count_queued_destroy_cells(const channel_t *chan,
const circuitmux_t *cmux);
/* Channel interface */
circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux,
destroy_cell_queue_t **destroy_queue_out);
void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
unsigned int n_cells);
void circuitmux_notify_xmit_destroy(circuitmux_t *cmux);
/* Circuit interface */
MOCK_DECL(void, circuitmux_attach_circuit, (circuitmux_t *cmux,
circuit_t *circ,
cell_direction_t direction));
MOCK_DECL(void, circuitmux_detach_circuit,
(circuitmux_t *cmux, circuit_t *circ));
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ);
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
unsigned int n_cells);
void circuitmux_append_destroy_cell(channel_t *chan,
circuitmux_t *cmux, circid_t circ_id,
uint8_t reason);
void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
channel_t *chan);
/* Optional interchannel comparisons for scheduling */
MOCK_DECL(int, circuitmux_compare_muxes,
(circuitmux_t *cmux_1, circuitmux_t *cmux_2));
#ifdef CIRCUITMUX_PRIVATE
#include "core/or/destroy_cell_queue_st.h"
/*
* Map of muxinfos for circuitmux_t to use; struct is defined below (name
* of struct must match HT_HEAD line).
*/
typedef HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t)
chanid_circid_muxinfo_map_t;
/*
* Structures for circuitmux.c
*/
struct circuitmux_t {
/* Keep count of attached, active circuits */
unsigned int n_circuits, n_active_circuits;
/* Total number of queued cells on all circuits */
unsigned int n_cells;
/*
* Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t
*/
chanid_circid_muxinfo_map_t *chanid_circid_map;
/** List of queued destroy cells */
destroy_cell_queue_t destroy_cell_queue;
/** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
* returned the destroy queue. Used to force alternation between
* destroy/non-destroy cells.
*
* XXXX There is no reason to think that alternating is a particularly good
* approach -- it's just designed to prevent destroys from starving other
* cells completely.
*/
unsigned int last_cell_was_destroy : 1;
/** Destroy counter: increment this when a destroy gets queued, decrement
* when we unqueue it, so we can test to make sure they don't starve.
*/
int64_t destroy_ctr;
/*
* Circuitmux policy; if this is non-NULL, it can override the built-
* in round-robin active circuits behavior. This is how EWMA works in
* the new circuitmux_t world.
*/
const circuitmux_policy_t *policy;
/* Policy-specific data */
circuitmux_policy_data_t *policy_data;
};
#endif /* defined(CIRCUITMUX_PRIVATE) */
#endif /* !defined(TOR_CIRCUITMUX_H) */
@@ -0,0 +1,138 @@
/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitmux_ewma.h
* \brief Header file for circuitmux_ewma.c
**/
#ifndef TOR_CIRCUITMUX_EWMA_H
#define TOR_CIRCUITMUX_EWMA_H
#include "core/or/or.h"
#include "core/or/circuitmux.h"
/* The public EWMA policy callbacks object. */
extern circuitmux_policy_t ewma_policy;
/* Externally visible EWMA functions */
void cmux_ewma_set_options(const or_options_t *options,
const networkstatus_t *consensus);
void circuitmux_ewma_free_all(void);
#ifdef CIRCUITMUX_EWMA_PRIVATE
/*** EWMA structures ***/
typedef struct cell_ewma_t cell_ewma_t;
typedef struct ewma_policy_data_t ewma_policy_data_t;
typedef struct ewma_policy_circ_data_t ewma_policy_circ_data_t;
/**
* The cell_ewma_t structure keeps track of how many cells a circuit has
* transferred recently. It keeps an EWMA (exponentially weighted moving
* average) of the number of cells flushed from the circuit queue onto a
* connection in channel_flush_from_first_active_circuit().
*/
struct cell_ewma_t {
/** The last 'tick' at which we recalibrated cell_count.
*
* A cell sent at exactly the start of this tick has weight 1.0. Cells sent
* since the start of this tick have weight greater than 1.0; ones sent
* earlier have less weight. */
unsigned int last_adjusted_tick;
/** The EWMA of the cell count. */
double cell_count;
/** True iff this is the cell count for a circuit's previous
* channel. */
unsigned int is_for_p_chan : 1;
/** The position of the circuit within the OR connection's priority
* queue. */
int heap_index;
};
struct ewma_policy_data_t {
circuitmux_policy_data_t base_;
/**
* Priority queue of cell_ewma_t for circuits with queued cells waiting
* for room to free up on the channel that owns this circuitmux. Kept
* in heap order according to EWMA. This was formerly in channel_t, and
* in or_connection_t before that.
*/
smartlist_t *active_circuit_pqueue;
/**
* The tick on which the cell_ewma_ts in active_circuit_pqueue last had
* their ewma values rescaled. This was formerly in channel_t, and in
* or_connection_t before that.
*/
unsigned int active_circuit_pqueue_last_recalibrated;
};
struct ewma_policy_circ_data_t {
circuitmux_policy_circ_data_t base_;
/**
* The EWMA count for the number of cells flushed from this circuit
* onto this circuitmux. Used to determine which circuit to flush
* from next. This was formerly in circuit_t and or_circuit_t.
*/
cell_ewma_t cell_ewma;
/**
* Pointer back to the circuit_t this is for; since we're separating
* out circuit selection policy like this, we can't attach cell_ewma_t
* to the circuit_t any more, so we can't use SUBTYPE_P directly to a
* circuit_t like before; instead get it here.
*/
circuit_t *circ;
};
#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
/*** Downcasts for the above types ***/
/**
* Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
* if the cast is impossible.
*/
static inline ewma_policy_data_t *
TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
{
if (!pol) return NULL;
else {
tor_assertf(pol->magic == EWMA_POL_DATA_MAGIC,
"Mismatch: %"PRIu32" != %"PRIu32,
pol->magic, EWMA_POL_DATA_MAGIC);
return DOWNCAST(ewma_policy_data_t, pol);
}
}
/**
* Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
* and assert if the cast is impossible.
*/
static inline ewma_policy_circ_data_t *
TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
{
if (!pol) return NULL;
else {
tor_assertf(pol->magic == EWMA_POL_CIRC_DATA_MAGIC,
"Mismatch: %"PRIu32" != %"PRIu32,
pol->magic, EWMA_POL_CIRC_DATA_MAGIC);
return DOWNCAST(ewma_policy_circ_data_t, pol);
}
}
STATIC unsigned cell_ewma_get_current_tick_and_fraction(double *remainder_out);
STATIC void cell_ewma_initialize_ticks(void);
#endif /* defined(CIRCUITMUX_EWMA_PRIVATE) */
#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */
@@ -0,0 +1,832 @@
/*
* Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitpadding.h
* \brief Header file for circuitpadding.c.
**/
#ifndef TOR_CIRCUITPADDING_H
#define TOR_CIRCUITPADDING_H
#include "trunnel/circpad_negotiation.h"
#include "lib/evloop/timers.h"
struct circuit_t;
struct origin_circuit_t;
struct cell_t;
/**
* Signed error return with the specific property that negative
* values mean error codes of various semantics, 0 means success,
* and positive values are unused.
*
* XXX: Tor uses this concept a lot but just calls it int. Should we move
* this somewhere centralized? Where?
*/
typedef int signed_error_t;
/**
* These constants specify the types of events that can cause
* transitions between state machine states.
*
* Note that SENT and RECV are relative to this endpoint. For
* relays, SENT means packets destined towards the client and
* RECV means packets destined towards the relay. On the client,
* SENT means packets destined towards the relay, where as RECV
* means packets destined towards the client.
*/
typedef enum {
/* A non-padding cell was received. */
CIRCPAD_EVENT_NONPADDING_RECV = 0,
/* A non-padding cell was sent. */
CIRCPAD_EVENT_NONPADDING_SENT = 1,
/* A padding cell (RELAY_COMMAND_DROP) was sent. */
CIRCPAD_EVENT_PADDING_SENT = 2,
/* A padding cell was received. */
CIRCPAD_EVENT_PADDING_RECV = 3,
/* We tried to schedule padding but we ended up picking the infinity bin
* which means that padding was delayed infinitely */
CIRCPAD_EVENT_INFINITY = 4,
/* All histogram bins are empty (we are out of tokens) */
CIRCPAD_EVENT_BINS_EMPTY = 5,
/* This state has used up its cell count */
CIRCPAD_EVENT_LENGTH_COUNT = 6
} circpad_event_t;
#define CIRCPAD_NUM_EVENTS ((int)CIRCPAD_EVENT_LENGTH_COUNT+1)
/** Boolean type that says if we decided to transition states or not */
typedef enum {
CIRCPAD_STATE_UNCHANGED = 0,
CIRCPAD_STATE_CHANGED = 1
} circpad_decision_t;
/** The type for the things in histogram bins (aka tokens) */
typedef uint32_t circpad_hist_token_t;
/** The type for histogram indexes (needs to be negative for errors) */
typedef int8_t circpad_hist_index_t;
/** The type for absolute time, from monotime_absolute_usec() */
typedef uint64_t circpad_time_t;
/** The type for timer delays, in microseconds */
typedef uint32_t circpad_delay_t;
#define CIRCPAD_DELAY_UNITS_PER_SECOND (1000*1000)
/**
* An infinite padding cell delay means don't schedule any padding --
* simply wait until a different event triggers a transition.
*
* This means that the maximum delay we can schedule is UINT32_MAX-1
* microseconds, or about 4300 seconds (1.25 hours).
* XXX: Is this enough if we want to simulate light, intermittent
* activity on an onion service?
*/
#define CIRCPAD_DELAY_INFINITE (UINT32_MAX)
/**
* This is the maximum delay that the circuit padding system can have, in
* seconds.
*/
#define CIRCPAD_DELAY_MAX_SECS \
((CIRCPAD_DELAY_INFINITE/CIRCPAD_DELAY_UNITS_PER_SECOND)+1)
/**
* Macro to clarify when we're checking the infinity bin.
*
* Works with either circpad_state_t or circpad_machine_runtime_t
*/
#define CIRCPAD_INFINITY_BIN(mi) ((mi)->histogram_len-1)
/**
* These constants form a bitfield that specifies when a state machine
* should be applied to a circuit.
*
* If any of these elements is set, then the circuit will be tested against
* that specific condition. If an element is unset, then we don't test it.
* (E.g., if neither NO_STREAMS or STREAMS are set, then we will not care
* whether a circuit has streams attached when we apply a state machine.)
*
* The helper function circpad_circuit_state() converts circuit state
* flags into this more compact representation.
*/
typedef enum {
/* Only apply machine if the circuit is still building */
CIRCPAD_CIRC_BUILDING = 1<<0,
/* Only apply machine if the circuit is open */
CIRCPAD_CIRC_OPENED = 1<<1,
/* Only apply machine if the circuit has no attached streams */
CIRCPAD_CIRC_NO_STREAMS = 1<<2,
/* Only apply machine if the circuit has attached streams */
CIRCPAD_CIRC_STREAMS = 1<<3,
/* Only apply machine if the circuit still allows RELAY_EARLY cells */
CIRCPAD_CIRC_HAS_RELAY_EARLY = 1<<4,
/* Only apply machine if the circuit has depleted its RELAY_EARLY cells
* allowance. */
CIRCPAD_CIRC_HAS_NO_RELAY_EARLY = 1<<5
} circpad_circuit_state_t;
/** Bitmask that says "apply this machine to all states" */
#define CIRCPAD_STATE_ALL \
(CIRCPAD_CIRC_BUILDING|CIRCPAD_CIRC_OPENED| \
CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_NO_STREAMS| \
CIRCPAD_CIRC_HAS_RELAY_EARLY|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY)
/**
* A compact circuit purpose bitfield mask that allows us to compactly
* specify which circuit purposes a machine should apply to.
*
* The helper function circpad_circ_purpose_to_mask() converts circuit
* purposes into bit positions in this bitmask.
*/
typedef uint32_t circpad_purpose_mask_t;
/** Bitmask that says "apply this machine to all purposes". */
#define CIRCPAD_PURPOSE_ALL (0xFFFFFFFF)
/**
* This type specifies all of the conditions that must be met before
* a client decides to initiate padding on a circuit.
*
* A circuit must satisfy every sub-field in this type in order
* to be considered to match the conditions.
*/
typedef struct circpad_machine_conditions_t {
/** Only apply the machine *if* the circuit has at least this many hops */
unsigned min_hops : 3;
/** Only apply the machine *if* vanguards are enabled */
unsigned requires_vanguards : 1;
/**
* This machine is ok to use if reduced padding is set in consensus
* or torrc. This machine will still be applied even if reduced padding
* is not set; this flag only acts to exclude machines that don't have
* it set when reduced padding is requested. Therefore, reduced padding
* machines should appear at the lowest priority in the padding machine
* lists (aka first in the list), so that non-reduced padding machines
* for the same purpose are given a chance to apply when reduced padding
* is not requested. */
unsigned reduced_padding_ok : 1;
/** Only apply the machine *if* the circuit's state matches any of
* the bits set in this bitmask. */
circpad_circuit_state_t apply_state_mask;
/** Only apply a machine *if* the circuit's purpose matches one
* of the bits set in this bitmask */
circpad_purpose_mask_t apply_purpose_mask;
/** Keep a machine if any of the circuits's state machine's match
* the bits set in this bitmask, but don't apply new machines if
* they match this mask. */
circpad_circuit_state_t keep_state_mask;
/** Keep a machine if any of the circuits's state machine's match
* the bits set in this bitmask, but don't apply new machines if
* they match this mask. */
circpad_purpose_mask_t keep_purpose_mask;
} circpad_machine_conditions_t;
/**
* Token removal strategy options.
*
* The WTF-PAD histograms are meant to specify a target distribution to shape
* traffic towards. This is accomplished by removing tokens from the histogram
* when either padding or non-padding cells are sent.
*
* When we see a non-padding cell at a particular time since the last cell, you
* remove a token from the corresponding delay bin. These flags specify
* which bin to choose if that bin is already empty.
*/
typedef enum {
/** Don't remove any tokens */
CIRCPAD_TOKEN_REMOVAL_NONE = 0,
/**
* Remove from the first non-zero higher bin index when current is zero.
* This is the recommended strategy from the Adaptive Padding paper. */
CIRCPAD_TOKEN_REMOVAL_HIGHER = 1,
/** Remove from the first non-zero lower bin index when current is empty. */
CIRCPAD_TOKEN_REMOVAL_LOWER = 2,
/** Remove from the closest non-zero bin index when current is empty. */
CIRCPAD_TOKEN_REMOVAL_CLOSEST = 3,
/** Remove from the closest bin by time value (since bins are
* exponentially spaced). */
CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC = 4,
/** Only remove from the exact bin corresponding to this delay. If
* the bin is 0, simply do nothing. Don't pick another bin. */
CIRCPAD_TOKEN_REMOVAL_EXACT = 5
} circpad_removal_t;
/**
* Distribution types supported by circpad_distribution_sample().
*
* These can be used instead of histograms for the inter-packet
* timing distribution, or to specify a distribution on the number
* of cells that can be sent while in a specific state of the state
* machine.
*
* Each distribution takes up to two parameters which are described below. */
typedef enum {
/* No probability distribution is used */
CIRCPAD_DIST_NONE = 0,
/* Uniform distribution: param1 is lower bound and param2 is upper bound */
CIRCPAD_DIST_UNIFORM = 1,
/* Logistic distribution: param1 is Mu, param2 is sigma. */
CIRCPAD_DIST_LOGISTIC = 2,
/* Log-logistic distribution: param1 is Alpha, param2 is 1.0/Beta */
CIRCPAD_DIST_LOG_LOGISTIC = 3,
/* Geometric distribution: param1 is 'p' (success probability) */
CIRCPAD_DIST_GEOMETRIC = 4,
/* Weibull distribution: param1 is k, param2 is Lambda */
CIRCPAD_DIST_WEIBULL = 5,
/* Generalized Pareto distribution: param1 is sigma, param2 is xi */
CIRCPAD_DIST_PARETO = 6
} circpad_distribution_type_t;
/**
* Distribution information.
*
* This type specifies a specific distribution above, as well as
* up to two parameters for that distribution. The specific
* per-distribution meaning of these parameters is specified
* in circpad_distribution_sample().
*/
typedef struct circpad_distribution_t {
circpad_distribution_type_t type;
double param1;
double param2;
} circpad_distribution_t;
/** State number type. Represents current state of state machine. */
typedef uint16_t circpad_statenum_t;
#define CIRCPAD_STATENUM_MAX (UINT16_MAX)
/** A histogram can be used to sample padding delays given a machine state.
* This constant defines the maximum histogram width (i.e. the max number of
* bins).
*
* The current limit is arbitrary and could be raised if there is a need,
* however too many bins will be hard to serialize in the future.
*
* Memory concerns are not so great here since the corresponding histogram and
* histogram_edges arrays are global and not per-circuit.
*
* If we ever upgrade this to a value that can't be represented by 8-bits we
* also need to upgrade circpad_hist_index_t.
*/
#define CIRCPAD_MAX_HISTOGRAM_LEN (100)
/**
* A state of a padding state machine. The information here are immutable and
* represent the initial form of the state; it does not get updated as things
* happen. The mutable information that gets updated in runtime are carried in
* a circpad_machine_runtime_t.
*
* This struct describes the histograms and/or probability distributions, as
* well as parameters of a single state in the adaptive padding machine.
* Instances of this struct exist in global circpad machine definitions that
* come from torrc or the consensus.
*/
typedef struct circpad_state_t {
/**
* If a histogram is used for this state, this specifies the number of bins
* of this histogram. Histograms must have at least 2 bins.
*
* In particular, the following histogram:
*
* Tokens
* +
* 10 | +----+
* 9 | | | +---------+
* 8 | | | | |
* 7 | | | +-----+ |
* 6 +----+ Bin+-----+ | +---------------+
* 5 | | #1 | | | | |
* | Bin| | Bin | Bin | Bin #4 | Bin #5 |
* | #0 | | #2 | #3 | | (infinity bin)|
* | | | | | | |
* | | | | | | |
* 0 +----+----+-----+-----+---------+---------------+
* 0 100 200 350 500 1000 inf microseconds
*
* would be specified the following way:
* histogram_len = 6;
* histogram[] = { 6, 10, 6, 7, 9, 6 }
* histogram_edges[] = { 0, 100, 200, 350, 500, 1000 }
*
* The final bin is called the "infinity bin" and if it's chosen we don't
* schedule any padding. The infinity bin is strange because its lower edge
* is the max value of possible non-infinite delay allowed by this histogram,
* and its upper edge is CIRCPAD_DELAY_INFINITE. You can tell if the infinity
* bin is chosen by inspecting its bin index or inspecting its upper edge.
*
* If a delay probability distribution is used for this state, this is set
* to 0. */
circpad_hist_index_t histogram_len;
/** The histogram itself: an array of uint16s of tokens, whose
* widths are exponentially spaced, in microseconds.
*
* This array must have histogram_len elements that are strictly
* monotonically increasing. */
circpad_hist_token_t histogram[CIRCPAD_MAX_HISTOGRAM_LEN];
/* The histogram bin edges in usec.
*
* Each element of this array specifies the left edge of the corresponding
* bin. The rightmost edge is always infinity and is not specified in this
* array.
*
* This array must have histogram_len elements. */
circpad_delay_t histogram_edges[CIRCPAD_MAX_HISTOGRAM_LEN+1];
/** Total number of tokens in this histogram. This is a constant and is *not*
* decremented every time we spend a token. It's used for initializing and
* refilling the histogram. */
uint32_t histogram_total_tokens;
/**
* Represents a delay probability distribution (aka IAT distribution). It's a
* parametrized way of encoding inter-packet delay information in
* microseconds. It can be used instead of histograms.
*
* If it is used, token_removal below must be set to
* CIRCPAD_TOKEN_REMOVAL_NONE.
*
* Start_usec, range_sec, and rtt_estimates are still applied to the
* results of sampling from this distribution (range_sec is used as a max).
*/
circpad_distribution_t iat_dist;
/* If a delay probability distribution is used, this is used as the max
* value we can sample from the distribution. However, RTT measurements and
* dist_added_shift gets applied on top of this value to derive the final
* padding delay. */
circpad_delay_t dist_max_sample_usec;
/* If a delay probability distribution is used and this is set, we will add
* this value on top of the value sampled from the IAT distribution to
* derive the final padding delay (We also add the RTT measurement if it's
* enabled.). */
circpad_delay_t dist_added_shift_usec;
/**
* The length dist is a parameterized way of encoding how long this
* state machine runs in terms of sent padding cells or all
* sent cells. Values are sampled from this distribution, clamped
* to max_len, and then start_len is added to that value.
*
* It may be specified instead of or in addition to
* the infinity bins and bins empty conditions. */
circpad_distribution_t length_dist;
/** A minimum length value, added to the output of length_dist */
uint16_t start_length;
/** A cap on the length value that can be sampled from the length_dist */
uint64_t max_length;
/** Should we decrement length when we see a nonpadding packet?
* XXX: Are there any machines that actually want to set this to 0? There may
* not be. OTOH, it's only a bit.. */
unsigned length_includes_nonpadding : 1;
/**
* This is an array that specifies the next state to transition to upon
* receipt an event matching the indicated array index.
*
* This aborts our scheduled packet and switches to the state
* corresponding to the index of the array. Tokens are filled upon
* this transition.
*
* States are allowed to transition to themselves, which means re-schedule
* a new padding timer. They are also allowed to temporarily "transition"
* to the "IGNORE" and "CANCEL" pseudo-states. See defines below
* for details on state behavior and meaning.
*/
circpad_statenum_t next_state[CIRCPAD_NUM_EVENTS];
/**
* If true, estimate the RTT from this relay to the exit/website and add that
* to start_usec for use as the histogram bin 0 start delay.
*
* Right now this is only supported for relay-side state machines.
*/
unsigned use_rtt_estimate : 1;
/** This specifies the token removal strategy to use upon padding and
* non-padding activity. */
circpad_removal_t token_removal;
} circpad_state_t;
/**
* The start state for this machine.
*
* In the original WTF-PAD, this is only used for transition to/from
* the burst state. All other fields are not used. But to simplify the
* code we've made it a first-class state. This has no performance
* consequences, but may make naive serialization of the state machine
* large, if we're not careful about how we represent empty fields.
*/
#define CIRCPAD_STATE_START 0
/**
* The burst state for this machine.
*
* In the original Adaptive Padding algorithm and in WTF-PAD
* (https://www.freehaven.net/anonbib/cache/ShWa-Timing06.pdf and
* https://www.cs.kau.se/pulls/hot/thebasketcase-wtfpad/), the burst
* state serves to detect bursts in traffic. This is done by using longer
* delays in its histogram, which represent the expected delays between
* bursts of packets in the target stream. If this delay expires without a
* real packet being sent, the burst state sends a padding packet and then
* immediately transitions to the gap state, which is used to generate
* a synthetic padding packet train. In this implementation, this transition
* needs to be explicitly specified in the burst state's transition events.
*
* Because of this flexibility, other padding mechanisms can transition
* between these two states arbitrarily, to encode other dynamics of
* target traffic.
*/
#define CIRCPAD_STATE_BURST 1
/**
* The gap state for this machine.
*
* In the original Adaptive Padding algorithm and in WTF-PAD, the gap
* state serves to simulate an artificial packet train composed of padding
* packets. It does this by specifying much lower inter-packet delays than
* the burst state, and transitioning back to itself after padding is sent
* if these timers expire before real traffic is sent. If real traffic is
* sent, it transitions back to the burst state.
*
* Again, in this implementation, these transitions must be specified
* explicitly, and other transitions are also permitted.
*/
#define CIRCPAD_STATE_GAP 2
/**
* End is a pseudo-state that causes the machine to go completely
* idle, and optionally get torn down (depending on the
* value of circpad_machine_spec_t.should_negotiate_end)
*
* End MUST NOT occupy a slot in the machine state array.
*/
#define CIRCPAD_STATE_END CIRCPAD_STATENUM_MAX
/**
* "Ignore" is a pseudo-state that means "do not react to this
* event".
*
* "Ignore" MUST NOT occupy a slot in the machine state array.
*/
#define CIRCPAD_STATE_IGNORE (CIRCPAD_STATENUM_MAX-1)
/**
* "Cancel" is a pseudo-state that means "cancel pending timers,
* but remain in your current state".
*
* Cancel MUST NOT occupy a slot in the machine state array.
*/
#define CIRCPAD_STATE_CANCEL (CIRCPAD_STATENUM_MAX-2)
/**
* Since we have 3 pseudo-states, the max state array length is
* up to one less than cancel's statenum.
*/
#define CIRCPAD_MAX_MACHINE_STATES (CIRCPAD_STATE_CANCEL-1)
/**
* Mutable padding machine info.
*
* This structure contains mutable information about a padding
* machine. The mutable information must be kept separate because
* it exists per-circuit, where as the machines themselves are global.
* This separation is done to conserve space in the circuit structure.
*
* This is the per-circuit state that changes regarding the global state
* machine. Some parts of it are optional (ie NULL).
*
* XXX: Play with layout to minimize space on x64 Linux (most common relay).
*/
typedef struct circpad_machine_runtime_t {
/** The callback pointer for the padding callbacks.
*
* These timers stick around the machineinfo until the machineinfo's circuit
* is closed, at which point the timer is cancelled. For this reason it's
* safe to assume that the machineinfo exists if this timer gets
* triggered. */
tor_timer_t *padding_timer;
/** The circuit for this machine */
struct circuit_t *on_circ;
/** A mutable copy of the histogram for the current state.
* NULL if remove_tokens is false for that state */
circpad_hist_token_t *histogram;
/** Length of the above histogram.
* XXX: This field *could* be removed at the expense of added
* complexity+overhead for reaching back into the immutable machine
* state every time we need to inspect the histogram. It's only a byte,
* though, so it seemed worth it.
*/
circpad_hist_index_t histogram_len;
/** Remove token from this index upon sending padding */
circpad_hist_index_t chosen_bin;
/** Stop padding/transition if this many cells sent */
uint64_t state_length;
#define CIRCPAD_STATE_LENGTH_INFINITE UINT64_MAX
/** A scaled count of padding packets sent, used to limit padding overhead.
* When this reaches UINT16_MAX, we cut it and nonpadding_sent in half. */
uint16_t padding_sent;
/** A scaled count of non-padding packets sent, used to limit padding
* overhead. When this reaches UINT16_MAX, we cut it and padding_sent in
* half. */
uint16_t nonpadding_sent;
/**
* Timestamp of the most recent cell event (sent, received, padding,
* non-padding), in seconds from approx_time().
*
* Used as an emergency break to stop holding padding circuits open.
*/
time_t last_cell_time_sec;
/**
* EWMA estimate of the RTT of the circuit from this hop
* to the exit end, in microseconds. */
circpad_delay_t rtt_estimate_usec;
/**
* The last time we got an event relevant to estimating
* the RTT. Monotonic time in microseconds since system
* start.
*/
circpad_time_t last_received_time_usec;
/**
* The time at which we scheduled a non-padding packet,
* or selected an infinite delay.
*
* Monotonic time in microseconds since system start.
* This is 0 if we haven't chosen a padding delay.
*/
circpad_time_t padding_scheduled_at_usec;
/** What state is this machine in? */
circpad_statenum_t current_state;
/** Machine counter, for shutdown sync.
*
* Set from circuit_t.padding_machine_ctr, which is incremented each
* padding machine instantiation.
*/
uint32_t machine_ctr;
/**
* True if we have scheduled a timer for padding.
*
* This is 1 if a timer is pending. It is 0 if
* no timer is scheduled. (It can be 0 even when
* padding_was_scheduled_at_usec is non-zero).
*/
unsigned is_padding_timer_scheduled : 1;
/**
* If this is true, we have seen full duplex behavior.
* Stop updating the RTT.
*/
unsigned stop_rtt_update : 1;
/** Max number of padding machines on each circuit. If changed,
* also ensure the machine_index bitwith supports the new size. */
#define CIRCPAD_MAX_MACHINES (2)
/** Which padding machine index was this for.
* (make sure changes to the bitwidth can support the
* CIRCPAD_MAX_MACHINES define). */
unsigned machine_index : 1;
} circpad_machine_runtime_t;
/** Helper macro to get an actual state machine from a machineinfo */
#define CIRCPAD_GET_MACHINE(machineinfo) \
((machineinfo)->on_circ->padding_machine[(machineinfo)->machine_index])
/**
* This specifies a particular padding machine to use after negotiation.
*
* The constants for machine_num_t are in trunnel.
* We want to be able to define extra numbers in the consensus/torrc, though.
*/
typedef uint8_t circpad_machine_num_t;
/** Global state machine structure from the consensus */
typedef struct circpad_machine_spec_t {
/* Just a user-friendly machine name for logs */
const char *name;
/** Global machine number */
circpad_machine_num_t machine_num;
/** Which machine index slot should this machine go into in
* the array on the circuit_t */
unsigned machine_index : 1;
/** Send a padding negotiate to shut down machine at end state? */
unsigned should_negotiate_end : 1;
// These next three fields are origin machine-only...
/** Origin side or relay side */
unsigned is_origin_side : 1;
/** Which hop in the circuit should we send padding to/from?
* 1-indexed (ie: hop #1 is guard, #2 middle, #3 exit). */
unsigned target_hopnum : 3;
/** If this flag is enabled, don't close circuits that use this machine even
* if another part of Tor wants to close this circuit.
*
* If this flag is set, the circuitpadding subsystem will close circuits the
* moment the machine transitions to the END state, and only if the circuit
* has already been asked to be closed by another part of Tor.
*
* Circuits that should have been closed but were kept open by a padding
* machine are re-purposed to CIRCUIT_PURPOSE_C_CIRCUIT_PADDING, hence
* machines should take that purpose into account if they are filtering
* circuits by purpose. */
unsigned manage_circ_lifetime : 1;
/** This machine only kills fascists if the following conditions are met. */
circpad_machine_conditions_t conditions;
/** How many padding cells can be sent before we apply overhead limits?
* XXX: Note that we can only allow up to 64k of padding cells on an
* otherwise quiet circuit. Is this enough? It's 33MB. */
uint16_t allowed_padding_count;
/** Padding percent cap: Stop padding if we exceed this percent overhead.
* 0 means no limit. Overhead is defined as percent of total traffic, so
* that we can use 0..100 here. This is the same definition as used in
* Prop#265. */
uint8_t max_padding_percent;
/** State array: indexed by circpad_statenum_t */
circpad_state_t *states;
/**
* Number of states this machine has (ie: length of the states array).
* XXX: This field is not needed other than for safety. */
circpad_statenum_t num_states;
} circpad_machine_spec_t;
void circpad_new_consensus_params(const networkstatus_t *ns);
int circpad_marked_circuit_for_padding(circuit_t *circ, int reason);
/**
* The following are event call-in points that are of interest to
* the state machines. They are called during cell processing. */
void circpad_deliver_unrecognized_cell_events(struct circuit_t *circ,
cell_direction_t dir);
void circpad_deliver_sent_relay_cell_events(struct circuit_t *circ,
uint8_t relay_command);
void circpad_deliver_recognized_relay_cell_events(struct circuit_t *circ,
uint8_t relay_command,
crypt_path_t *layer_hint);
/** Cell events are delivered by the above delivery functions */
void circpad_cell_event_nonpadding_sent(struct circuit_t *on_circ);
void circpad_cell_event_nonpadding_received(struct circuit_t *on_circ);
void circpad_cell_event_padding_sent(struct circuit_t *on_circ);
void circpad_cell_event_padding_received(struct circuit_t *on_circ);
/** Internal events are events the machines send to themselves */
circpad_decision_t
circpad_internal_event_infinity(circpad_machine_runtime_t *mi);
circpad_decision_t
circpad_internal_event_bins_empty(circpad_machine_runtime_t *);
circpad_decision_t circpad_internal_event_state_length_up(
circpad_machine_runtime_t *);
/** Machine creation events are events that cause us to set up or
* tear down padding state machines. */
void circpad_machine_event_circ_added_hop(struct origin_circuit_t *on_circ);
void circpad_machine_event_circ_built(struct origin_circuit_t *circ);
void circpad_machine_event_circ_purpose_changed(struct origin_circuit_t *circ);
void circpad_machine_event_circ_has_streams(struct origin_circuit_t *circ);
void circpad_machine_event_circ_has_no_streams(struct origin_circuit_t *circ);
void
circpad_machine_event_circ_has_no_relay_early(struct origin_circuit_t *circ);
void circpad_machines_init(void);
void circpad_machines_free(void);
void circpad_register_padding_machine(circpad_machine_spec_t *machine,
smartlist_t *machine_list);
void circpad_machine_states_init(circpad_machine_spec_t *machine,
circpad_statenum_t num_states);
void circpad_circuit_free_all_machineinfos(struct circuit_t *circ);
bool circpad_padding_is_from_expected_hop(struct circuit_t *circ,
crypt_path_t *from_hop);
/** Serializaton functions for writing to/from torrc and consensus */
char *circpad_machine_spec_to_string(const circpad_machine_spec_t *machine);
const circpad_machine_spec_t *circpad_string_to_machine(const char *str);
/* Padding negotiation between client and middle */
signed_error_t circpad_handle_padding_negotiate(struct circuit_t *circ,
struct cell_t *cell);
signed_error_t circpad_handle_padding_negotiated(struct circuit_t *circ,
struct cell_t *cell,
crypt_path_t *layer_hint);
signed_error_t circpad_negotiate_padding(struct origin_circuit_t *circ,
circpad_machine_num_t machine,
uint8_t target_hopnum,
uint8_t command,
uint32_t machine_ctr);
bool circpad_padding_negotiated(struct circuit_t *circ,
circpad_machine_num_t machine,
uint8_t command,
uint8_t response,
uint32_t machine_ctr);
circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose);
int circpad_check_received_cell(cell_t *cell, circuit_t *circ,
crypt_path_t *layer_hint,
const relay_header_t *rh);
MOCK_DECL(circpad_decision_t,
circpad_machine_schedule_padding,(circpad_machine_runtime_t *));
MOCK_DECL(circpad_decision_t,
circpad_machine_spec_transition, (circpad_machine_runtime_t *mi,
circpad_event_t event));
circpad_decision_t circpad_send_padding_cell_for_callback(
circpad_machine_runtime_t *mi);
void circpad_free_all(void);
#ifdef CIRCUITPADDING_PRIVATE
STATIC void machine_spec_free_(circpad_machine_spec_t *m);
#define machine_spec_free(chan) \
FREE_AND_NULL(circpad_machine_spec_t,machine_spec_free_, (m))
STATIC circpad_delay_t
circpad_machine_sample_delay(circpad_machine_runtime_t *mi);
STATIC bool
circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi);
STATIC circpad_delay_t
circpad_histogram_bin_to_usec(const circpad_machine_runtime_t *mi,
circpad_hist_index_t bin);
STATIC const circpad_state_t *
circpad_machine_current_state(const circpad_machine_runtime_t *mi);
STATIC void circpad_machine_remove_token(circpad_machine_runtime_t *mi);
STATIC circpad_hist_index_t circpad_histogram_usec_to_bin(
const circpad_machine_runtime_t *mi,
circpad_delay_t us);
STATIC circpad_machine_runtime_t *circpad_circuit_machineinfo_new(
struct circuit_t *on_circ,
int machine_index);
STATIC void circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi,
circpad_delay_t target_bin_us);
STATIC void circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi,
circpad_delay_t target_bin_us);
STATIC void circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi,
circpad_delay_t target_bin_us,
bool use_usec);
STATIC void circpad_machine_setup_tokens(circpad_machine_runtime_t *mi);
MOCK_DECL(STATIC signed_error_t,
circpad_send_command_to_hop,(struct origin_circuit_t *circ, uint8_t hopnum,
uint8_t relay_command, const uint8_t *payload,
ssize_t payload_len));
MOCK_DECL(STATIC const node_t *,
circuit_get_nth_node,(origin_circuit_t *circ, int hop));
STATIC circpad_delay_t
histogram_get_bin_upper_bound(const circpad_machine_runtime_t *mi,
circpad_hist_index_t bin);
STATIC void
circpad_add_matching_machines(origin_circuit_t *on_circ,
smartlist_t *machines_sl);
#ifdef TOR_UNIT_TESTS
extern smartlist_t *origin_padding_machines;
extern smartlist_t *relay_padding_machines;
#endif
#endif /* defined(CIRCUITPADDING_PRIVATE) */
#endif /* !defined(TOR_CIRCUITPADDING_H) */
@@ -0,0 +1,35 @@
/* Copyright (c) 2018 The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitpadding_machines.h
* \brief Header file for circuitpadding_machines.c.
**/
#ifndef TOR_CIRCUITPADDING_MACHINES_H
#define TOR_CIRCUITPADDING_MACHINES_H
void circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl);
void circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl);
void circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl);
void circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl);
#ifdef CIRCUITPADDING_MACHINES_PRIVATE
/** State of the padding machines that actually sends padding */
#define CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP CIRCPAD_STATE_BURST
/** Constants defining the amount of padding that a machine will send to hide
* HS circuits. The actual value is sampled uniformly random between the
* min/max values.
*/
/** Minimum number of relay-side padding cells to be sent by this machine */
#define INTRO_MACHINE_MINIMUM_PADDING 7
/** Maximum number of relay-side padding cells to be sent by this machine.
* The actual value will be sampled between the min and max.*/
#define INTRO_MACHINE_MAXIMUM_PADDING 10
#endif /* defined(CIRCUITPADDING_MACHINES_PRIVATE) */
#endif /* !defined(TOR_CIRCUITPADDING_MACHINES_H) */
@@ -0,0 +1,212 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuitstats.h
* \brief Header file for circuitstats.c
**/
#ifndef TOR_CIRCUITSTATS_H
#define TOR_CIRCUITSTATS_H
const circuit_build_times_t *get_circuit_build_times(void);
circuit_build_times_t *get_circuit_build_times_mutable(void);
double get_circuit_build_close_time_ms(void);
double get_circuit_build_timeout_ms(void);
int circuit_build_times_disabled(const or_options_t *options);
int circuit_build_times_disabled_(const or_options_t *options,
int ignore_consensus);
/** A build_time_t is milliseconds */
typedef uint32_t build_time_t;
int circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt);
void circuit_build_times_update_state(const circuit_build_times_t *cbt,
or_state_t *state);
int circuit_build_times_parse_state(circuit_build_times_t *cbt,
or_state_t *state);
void circuit_build_times_count_timeout(circuit_build_times_t *cbt,
int did_onehop);
int circuit_build_times_count_close(circuit_build_times_t *cbt,
int did_onehop, time_t start_time);
void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
int circuit_build_times_add_time(circuit_build_times_t *cbt,
build_time_t time);
int circuit_build_times_needs_circuits(const circuit_build_times_t *cbt);
void circuit_build_times_handle_completed_hop(origin_circuit_t *circ);
int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt);
void circuit_build_times_init(circuit_build_times_t *cbt);
void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
const networkstatus_t *ns);
double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
void circuit_build_times_update_last_circ(circuit_build_times_t *cbt);
void circuit_build_times_mark_circ_as_measurement_only(origin_circuit_t *circ);
void circuit_build_times_reset(circuit_build_times_t *cbt);
/** Total size of the circuit timeout history to accumulate.
* 1000 is approx 2.5 days worth of continual-use circuits. */
#define CBT_NCIRCUITS_TO_OBSERVE 1000
/** Width of the histogram bins in milliseconds */
#define CBT_BIN_WIDTH ((build_time_t)10)
/** Number of modes to use in the weighted-avg computation of Xm */
#define CBT_DEFAULT_NUM_XM_MODES 10
#define CBT_MIN_NUM_XM_MODES 1
#define CBT_MAX_NUM_XM_MODES 20
/**
* CBT_BUILD_ABANDONED is our flag value to represent a force-closed
* circuit (Aka a 'right-censored' pareto value).
*/
#define CBT_BUILD_ABANDONED ((build_time_t)(INT32_MAX-1))
#define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX))
/** Save state every 10 circuits */
#define CBT_SAVE_STATE_EVERY 10
/* Circuit build times consensus parameters */
/**
* How long to wait before actually closing circuits that take too long to
* build in terms of CDF quantile.
*/
#define CBT_DEFAULT_CLOSE_QUANTILE 99
#define CBT_MIN_CLOSE_QUANTILE CBT_MIN_QUANTILE_CUTOFF
#define CBT_MAX_CLOSE_QUANTILE CBT_MAX_QUANTILE_CUTOFF
/**
* How many circuits count as recent when considering if the
* connection has gone gimpy or changed.
*/
#define CBT_DEFAULT_RECENT_CIRCUITS 20
#define CBT_MIN_RECENT_CIRCUITS 3
#define CBT_MAX_RECENT_CIRCUITS 1000
/**
* Maximum count of timeouts that finish the first hop in the past
* RECENT_CIRCUITS before calculating a new timeout.
*
* This tells us whether to abandon timeout history and set
* the timeout back to whatever circuit_build_times_get_initial_timeout()
* gives us.
*/
#define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10)
#define CBT_MIN_MAX_RECENT_TIMEOUT_COUNT 3
#define CBT_MAX_MAX_RECENT_TIMEOUT_COUNT 10000
/** Minimum circuits before estimating a timeout */
#define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100
#define CBT_MIN_MIN_CIRCUITS_TO_OBSERVE 1
#define CBT_MAX_MIN_CIRCUITS_TO_OBSERVE 10000
/** Cutoff percentile on the CDF for our timeout estimation. */
#define CBT_DEFAULT_QUANTILE_CUTOFF 80
#define CBT_MIN_QUANTILE_CUTOFF 10
#define CBT_MAX_QUANTILE_CUTOFF 99
double circuit_build_times_quantile_cutoff(void);
/** How often in seconds should we build a test circuit */
#define CBT_DEFAULT_TEST_FREQUENCY 10
#define CBT_MIN_TEST_FREQUENCY 1
#define CBT_MAX_TEST_FREQUENCY INT32_MAX
/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (CBT_BIN_WIDTH)
#define CBT_MIN_TIMEOUT_MIN_VALUE CBT_BIN_WIDTH
#define CBT_MAX_TIMEOUT_MIN_VALUE INT32_MAX
/** Initial circuit build timeout in milliseconds */
#define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000)
#define CBT_MIN_TIMEOUT_INITIAL_VALUE CBT_MIN_TIMEOUT_MIN_VALUE
#define CBT_MAX_TIMEOUT_INITIAL_VALUE INT32_MAX
int32_t circuit_build_times_initial_timeout(void);
#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < CBT_MIN_MAX_RECENT_TIMEOUT_COUNT
#error "RECENT_CIRCUITS is set too low."
#endif
#ifdef CIRCUITSTATS_PRIVATE
STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile);
STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
/* Network liveness functions */
STATIC int circuit_build_times_network_check_changed(
circuit_build_times_t *cbt);
STATIC build_time_t circuit_build_times_get_xm(circuit_build_times_t *cbt);
#endif /* defined(CIRCUITSTATS_PRIVATE) */
#ifdef TOR_UNIT_TESTS
build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
double q_lo, double q_hi);
double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
double quantile, double time_ms);
void circuitbuild_running_unit_tests(void);
#endif /* defined(TOR_UNIT_TESTS) */
/* Network liveness functions */
void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
int circuit_build_times_network_check_live(const circuit_build_times_t *cbt);
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
/** Information about the state of our local network connection */
typedef struct {
/** The timestamp we last completed a TLS handshake or received a cell */
time_t network_last_live;
/** If the network is not live, how many timeouts has this caused? */
int nonlive_timeouts;
/** Circular array of circuits that have made it to the first hop. Slot is
* 1 if circuit timed out, 0 if circuit succeeded */
int8_t *timeouts_after_firsthop;
/** Number of elements allocated for the above array */
int num_recent_circs;
/** Index into circular array. */
int after_firsthop_idx;
} network_liveness_t;
/** Structure for circuit build times history */
struct circuit_build_times_t {
/** The circular array of recorded build times in milliseconds */
build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
/** Current index in the circuit_build_times circular array */
int build_times_idx;
/** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */
int total_build_times;
/** Information about the state of our local network connection */
network_liveness_t liveness;
/** Last time we built a circuit. Used to decide to build new test circs */
time_t last_circ_at;
/** "Minimum" value of our pareto distribution (actually mode) */
build_time_t Xm;
/** alpha exponent for pareto dist. */
double alpha;
/** Have we computed a timeout? */
int have_computed_timeout;
/** The exact value for that timeout in milliseconds. Stored as a double
* to maintain precision from calculations to and from quantile value. */
double timeout_ms;
/** How long we wait before actually closing the circuit. */
double close_ms;
/** Total succeeded counts. Old measurements may be scaled downward if
* we've seen a lot of circuits. */
uint32_t num_circ_succeeded;
/** Total timeout counts. Old measurements may be scaled downward if
* we've seen a lot of circuits. */
uint32_t num_circ_timeouts;
/** Total closed counts. Old measurements may be scaled downward if
* we've seen a lot of circuits.*/
uint32_t num_circ_closed;
};
#endif /* !defined(TOR_CIRCUITSTATS_H) */
@@ -0,0 +1,111 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file circuituse.h
* \brief Header file for circuituse.c.
**/
#ifndef TOR_CIRCUITUSE_H
#define TOR_CIRCUITUSE_H
void circuit_expire_building(void);
void circuit_expire_waiting_for_better_guard(void);
void circuit_remove_handled_ports(smartlist_t *needed_ports);
int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port,
int min);
void circuit_log_ancient_one_hop_circuits(int age);
#if 0
int circuit_conforms_to_options(const origin_circuit_t *circ,
const or_options_t *options);
#endif
void circuit_build_needed_circs(time_t now);
void circuit_expire_old_circs_as_needed(time_t now);
void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn);
void circuit_expire_old_circuits_serverside(time_t now);
void reset_bandwidth_test(void);
int circuit_enough_testing_circs(void);
void circuit_has_opened(origin_circuit_t *circ);
void circuit_try_attaching_streams(origin_circuit_t *circ);
void circuit_build_failed(origin_circuit_t *circ);
/** Flag to set when a circuit should have only a single hop. */
#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0)
/** Flag to set when a circuit needs to be built of high-uptime nodes */
#define CIRCLAUNCH_NEED_UPTIME (1<<1)
/** Flag to set when a circuit needs to be built of high-capacity nodes */
#define CIRCLAUNCH_NEED_CAPACITY (1<<2)
/** Flag to set when the last hop of a circuit doesn't need to be an
* exit node. */
#define CIRCLAUNCH_IS_INTERNAL (1<<3)
/** Flag to set when we are trying to launch a self-testing circuit to our
* IPv6 ORPort. We need to apply some additional filters on the second-last
* node in the circuit. (We are both the client and the last node in the
* circuit.) */
#define CIRCLAUNCH_IS_IPV6_SELFTEST (1<<5)
/** Flag to set when a circuit needs the exit to support conflux. */
#define CIRCLAUNCH_NEED_CONFLUX (1<<6)
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
int flags);
origin_circuit_t *circuit_launch(uint8_t purpose, int flags);
void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
origin_circuit_t *circ,
crypt_path_t *cpath);
int connection_ap_handshake_attach_circuit(entry_connection_t *conn);
void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose);
int hostname_in_track_host_exits(const or_options_t *options,
const char *address);
void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
int circuit_purpose_is_hidden_service(uint8_t);
/* Series of helper functions for hidden services. */
bool circuit_purpose_is_hs_client(const uint8_t purpose);
bool circuit_purpose_is_hs_service(const uint8_t purpose);
bool circuit_purpose_is_hs_vanguards(const uint8_t purpose);
bool circuit_is_hs_v3(const circuit_t *circ);
int circuit_is_acceptable(const origin_circuit_t *origin_circ,
const entry_connection_t *conn,
int must_be_open, uint8_t purpose,
int need_uptime, int need_internal,
time_t now);
int circuit_should_use_vanguards(uint8_t);
void circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
#ifdef TOR_UNIT_TESTS
/* Used only by circuituse.c and test_circuituse.c */
STATIC int circuit_is_available_for_use(const circuit_t *circ);
STATIC int needs_exit_circuits(time_t now,
int *port_needs_uptime,
int *port_needs_capacity);
STATIC int needs_hs_server_circuits(time_t now,
int num_uptime_internal);
STATIC int needs_hs_client_circuits(time_t now,
int *needs_uptime,
int *needs_capacity,
int num_internal,
int num_uptime_internal);
STATIC int needs_circuits_for_build(int num);
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* !defined(TOR_CIRCUITUSE_H) */
@@ -0,0 +1,30 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file command.h
* \brief Header file for command.c.
**/
#ifndef TOR_COMMAND_H
#define TOR_COMMAND_H
#include "core/or/channel.h"
void command_process_cell(channel_t *chan, cell_t *cell);
void command_setup_channel(channel_t *chan);
void command_setup_listener(channel_listener_t *chan_l);
const char *cell_command_to_string(uint8_t command);
extern uint64_t stats_n_padding_cells_processed;
extern uint64_t stats_n_create_cells_processed;
extern uint64_t stats_n_created_cells_processed;
extern uint64_t stats_n_relay_cells_processed;
extern uint64_t stats_n_destroy_cells_processed;
#endif /* !defined(TOR_COMMAND_H) */
@@ -0,0 +1,84 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux.h
* \brief Public APIs for conflux multipath support
**/
#ifndef TOR_CONFLUX_H
#define TOR_CONFLUX_H
#include "core/or/circuit_st.h"
#include "core/or/conflux_st.h"
typedef struct conflux_t conflux_t;
typedef struct conflux_leg_t conflux_leg_t;
/** Helpers to iterate over legs with better semantic. */
#define CONFLUX_FOR_EACH_LEG_BEGIN(cfx, var) \
SMARTLIST_FOREACH_BEGIN(cfx->legs, conflux_leg_t *, var)
#define CONFLUX_FOR_EACH_LEG_END(var) \
SMARTLIST_FOREACH_END(var)
/** Helper: Return the number of legs a conflux object has. */
#define CONFLUX_NUM_LEGS(cfx) (smartlist_len(cfx->legs))
/** A cell for the out-of-order queue.
* XXX: Consider trying to use packed_cell_t instead here? */
typedef struct {
/**
* Absolute sequence number of this cell, computed from the
* relative sequence number of the conflux cell. */
uint64_t seq;
/**
* Heap index of this cell, for use in in the conflux_t ooo_q heap.
*/
int heap_idx;
/** The cell here is always guaranteed to have removed its
* extra conflux sequence number, for ease of processing */
cell_t cell;
} conflux_cell_t;
size_t conflux_handle_oom(size_t bytes_to_remove);
uint64_t conflux_get_total_bytes_allocation(void);
uint64_t conflux_get_circ_bytes_allocation(const circuit_t *circ);
void conflux_update_rtt(conflux_t *cfx, circuit_t *circ, uint64_t rtt_usec);
circuit_t *conflux_decide_circ_for_send(conflux_t *cfx,
circuit_t *orig_circ,
uint8_t relay_command);
circuit_t *conflux_decide_next_circ(conflux_t *cfx);
int conflux_process_switch_command(circuit_t *in_circ,
crypt_path_t *layer_hint, cell_t *cell,
relay_header_t *rh);
bool conflux_should_multiplex(int relay_command);
bool conflux_process_cell(conflux_t *cfx, circuit_t *in_circ,
crypt_path_t *layer_hint,
cell_t *cell);
conflux_cell_t *conflux_dequeue_cell(conflux_t *cfx);
void conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ,
uint8_t relay_command);
/* Private section starts. */
#ifdef TOR_CONFLUX_PRIVATE
const struct congestion_control_t *circuit_ccontrol(const circuit_t *);
conflux_leg_t *conflux_get_leg(conflux_t *cfx, const circuit_t *circ);
uint64_t conflux_get_max_seq_recv(const conflux_t *cfx);
uint64_t conflux_get_max_seq_sent(const conflux_t *cfx);
/*
* Unit tests declaractions.
*/
#ifdef TOR_UNIT_TESTS
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(TOR_CONFLUX_PRIVATE) */
#endif /* !defined(TOR_CONFLUX_H) */
@@ -0,0 +1,50 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_cell.h
* \brief Header file for conflux_cell.c.
**/
#ifndef TOR_CONFLUX_CELL_H
#define TOR_CONFLUX_CELL_H
#include "core/or/or.h"
typedef struct conflux_cell_link_t {
uint8_t version;
uint8_t desired_ux;
uint8_t nonce[DIGEST256_LEN];
uint64_t last_seqno_sent;
uint64_t last_seqno_recv;
} conflux_cell_link_t;
conflux_cell_link_t *conflux_cell_new_link(const uint8_t *nonce,
uint64_t last_sent,
uint64_t last_recv,
uint8_t ux);
conflux_cell_link_t *conflux_cell_parse_link(const cell_t *cell,
const uint16_t cell_len);
conflux_cell_link_t *conflux_cell_parse_linked(const cell_t *cell,
const uint16_t cell_le);
uint32_t conflux_cell_parse_switch(const cell_t *cell,
const uint16_t rh_len);
bool conflux_cell_send_link(const conflux_cell_link_t *link,
origin_circuit_t *circ);
bool conflux_cell_send_linked(const conflux_cell_link_t *link,
or_circuit_t *circ);
bool conflux_cell_send_linked_ack(origin_circuit_t *circ);
bool conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq);
#ifdef TOR_UNIT_TESTS
STATIC ssize_t
build_link_cell(const conflux_cell_link_t *link, uint8_t *cell_out);
#endif /* TOR_UNIT_TESTS */
#endif /* TOR_CONFLUX_CELL_H */
@@ -0,0 +1,30 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_params.h
* \brief Header file for conflux_params.c.
**/
#ifndef TOR_CONFLUX_PARAMS_H
#define TOR_CONFLUX_PARAMS_H
#include "core/or/or.h"
bool conflux_is_enabled(const struct circuit_t *circ);
uint8_t conflux_params_get_max_linked_set(void);
uint8_t conflux_params_get_max_prebuilt(void);
uint8_t conflux_params_get_max_unlinked_leg_retry(void);
uint8_t conflux_params_get_num_legs_set(void);
uint8_t conflux_params_get_max_legs_set(void);
uint8_t conflux_params_get_drain_pct(void);
uint8_t conflux_params_get_send_pct(void);
void conflux_params_new_consensus(const networkstatus_t *ns);
#ifdef TOR_UNIT_TESTS
extern uint32_t max_unlinked_leg_retry;
#endif
#endif /* TOR_CONFLUX_PARAMS_H */
@@ -0,0 +1,51 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_pool.h
* \brief Header file for conflux_pool.c.
**/
#ifndef TOR_CONFLUX_POOL_H
#define TOR_CONFLUX_POOL_H
#include "core/or/or.h"
void conflux_pool_init(void);
void conflux_pool_free_all(void);
origin_circuit_t *conflux_get_circ_for_conn(const entry_connection_t *conn,
time_t now);
void conflux_predict_new(time_t now);
bool conflux_launch_leg(const uint8_t *nonce);
void conflux_add_guards_to_exclude_list(const origin_circuit_t *circ,
smartlist_t *excluded);
void conflux_add_middles_to_exclude_list(const origin_circuit_t *circ,
smartlist_t *excluded);
void conflux_circuit_has_closed(circuit_t *circ);
void conflux_circuit_has_opened(origin_circuit_t *orig_circ);
void conflux_circuit_about_to_free(circuit_t *circ);
void conflux_process_link(circuit_t *circ, const cell_t *cell,
const uint16_t cell_len);
void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint,
const cell_t *cell, const uint16_t cell_len);
void conflux_process_linked_ack(circuit_t *circ);
typedef struct conflux_t conflux_t;
void conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client);
#ifdef TOR_UNIT_TESTS
bool launch_new_set(int num_legs);
digest256map_t *get_linked_pool(bool is_client);
digest256map_t *get_unlinked_pool(bool is_client);
extern uint8_t DEFAULT_CLIENT_UX;
extern uint8_t DEFAULT_EXIT_UX;
#endif /* defined(UNIT_TESTS) */
#endif /* TOR_CONFLUX_POOL_H */
@@ -0,0 +1,142 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_st.h
* \brief Structure definitions for conflux multipath
**/
#ifndef CONFLUX_ST_H
#define CONFLUX_ST_H
#include "core/or/circuit_st.h"
#include "core/or/cell_st.h"
#include "lib/defs/digest_sizes.h"
/**
* Specifies which conflux alg is in use.
*/
typedef enum {
CONFLUX_ALG_MINRTT = 0,
CONFLUX_ALG_LOWRTT = 1,
CONFLUX_ALG_CWNDRTT = 2,
} conflux_alg_t;
/** XXX: Cached consensus params+scheduling alg */
struct conflux_params_t {
conflux_alg_t alg;
};
struct conflux_leg_t {
/**
* For computing ooo_q insertion sequence numbers: Highest absolute
* sequence number received on each leg, before delivery.
*
* As a receiver, this allows us to compute the absolute sequence number
* of a cell for delivery or insertion into the ooo_q. When a SWITCH cell
* is received on a leg, the absolute sequence number of that cell is
* the relative sequence number in that cell, plus the absolute sequence
* number of that leg from this array. The leg's sequence number
* is then updated to this value immediately.
*
* In this way, we are able to assign absolute sequence numbers to cells
* immediately, regardless of how many legs or leg switches have occurred,
* and regardless of the delivery status of each cell versus if it must be
* queued.
*/
uint64_t last_seq_recv;
/**
* For relative sequencing: Highest absolute sequence number sent on each
* circuit. The overall absolute current sent sequence number is the highest
* of these values.
*
* As a sender, this allows us to compute a relative sequence number when
* switching legs. When switching legs, the sender looks up its current
* absolute sequence number as the maximum of all legs. The sender then
* compares that to the current sequence number on the leg it is about to
* send on, and then computes the relative sequence number as the difference
* between the overall absolute sequence number and the sequence number
* from the sending leg.
*
* In this way, we can use much smaller relative sequence numbers on the
* wire, as opposed to larger absolute values, at the expense of this
* bookkeeping overhead on each end.
*/
uint64_t last_seq_sent;
/**
* Current round-trip of the circuit, in usec.
*
* XXX: In theory, we could use the congestion control RTTs directly off the
* circs, but congestion control code has assumptions about the RTT being 0
* at the start of the circuit, which will *not* be the case here, because we
* get an RTT off the link circuit. */
uint64_t circ_rtts_usec;
/** Exit side only: When was the LINKED cell sent? Used for RTT measurement
* that sets circ_rtts_usec when the LINKED_ACK is received. */
uint64_t linked_sent_usec;
/** Circuit of this leg. */
circuit_t *circ;
};
/** Fields for conflux multipath support */
struct conflux_t {
/** Cached parameters for this circuit */
struct conflux_params_t params;
/**
* List of all linked conflux_leg_t for this set. Once a leg is in that list,
* it can be used to transmit data. */
smartlist_t *legs;
/**
* Out-of-order priority queue of conflux_cell_t *, heapified
* on conflux_cell_t.seq number (lowest at top of heap).
*
* XXX: We are most likely to insert cells at either the head or the tail.
* Verify that is fast-path wrt smartlist priority queues, and not a memmove
* nightmare. If so, we may need a real linked list, or a packed_cell_t list.
*/
smartlist_t *ooo_q;
/**
* Absolute sequence number of cells delivered to streams since start.
* (ie: this is updated *after* dequeue from the ooo_q priority queue). */
uint64_t last_seq_delivered;
/**
* The estimated remaining number of cells we can send on this circuit
* before we are allowed to switch legs. */
uint64_t cells_until_switch;
/** Current circuit leg. Only use this with conflux_get_circ_for_leg() for
* bounds checking. */
struct conflux_leg_t *curr_leg;
/** Previous circuit leg. Only use this with conflux_get_circ_for_leg() for
* bounds checking. */
struct conflux_leg_t *prev_leg;
/** The nonce that joins these */
uint8_t nonce[DIGEST256_LEN];
/** Indicate if this conflux set is in full teardown. We mark it at the first
* close in case of a total teardown so we avoid recursive calls of circuit
* mark for close. */
bool in_full_teardown;
/** Number of leg launch that we've done for this set. We keep this value
* because there is a maximum allowed in order to avoid side channel(s). */
unsigned int num_leg_launch;
/**
* PolicyHint: Predicted ports/protocol shorthand..
*
* XXX: This might be redundant to the circuit's exitpolicy.
*/
};
#endif /* !defined(CONFLUX_ST_H) */
@@ -0,0 +1,23 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_sys.h
* \brief Header file for conflux_sys.c.
**/
#ifndef TOR_CONFLUX_SYS_H
#define TOR_CONFLUX_SYS_H
extern const struct subsys_fns_t sys_conflux;
/**
* Subsystem level.
*
* Defined here so that it can be shared between the real and stub
* definitions.
**/
#define CONFLUX_SUBSYS_LEVEL (10)
#endif /* TOR_CONFLUX_SYS_H */
@@ -0,0 +1,63 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_util.h
* \brief Header file for conflux_util.c.
**/
#ifndef TOR_CONFLUX_UTIL_H
#define TOR_CONFLUX_UTIL_H
/* Forward decls */
typedef struct edge_connection_t edge_connection_t;
typedef struct crypt_path_t crypt_path_t;
typedef struct origin_circuit_t origin_circuit_t;
typedef struct conflux_t conflux_t;
/* True iff the given circuit_t circ is conflux related. */
static inline bool
CIRCUIT_IS_CONFLUX(const circuit_t *circ)
{
if (circ->conflux_pending_nonce) {
if (CIRCUIT_IS_ORIGIN(circ))
tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED);
return true;
} else if (circ->conflux) {
if (CIRCUIT_IS_ORIGIN(circ))
tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
return true;
} else {
/* We don't assert on purposes here because we can end up in this branch
* with circ->conflux being NULL but for a conflux purpose. This happens in
* the about_to_free() code path. */
return false;
}
}
const uint8_t *conflux_get_nonce(const circuit_t *circ);
uint64_t conflux_get_circ_rtt(const circuit_t *circ);
int circuit_get_package_window(circuit_t *circ,
const crypt_path_t *cpath);
bool conflux_can_send(conflux_t *cfx);
bool edge_uses_cpath(const edge_connection_t *conn,
const crypt_path_t *cpath);
crypt_path_t *conflux_get_destination_hop(circuit_t *circ);
bool conflux_validate_source_hop(circuit_t *in_circ,
crypt_path_t *layer_hint);
uint64_t edge_get_max_rtt(const edge_connection_t *stream);
bool relay_crypt_from_last_hop(const origin_circuit_t *circ,
const crypt_path_t *layer_hint);
void conflux_update_p_streams(origin_circuit_t *, edge_connection_t *);
void conflux_update_half_streams(origin_circuit_t *, smartlist_t *);
void conflux_update_n_streams(or_circuit_t *, edge_connection_t *);
void conflux_update_resolving_streams(or_circuit_t *, edge_connection_t *);
void conflux_sync_circ_fields(conflux_t *cfx, origin_circuit_t *ref_circ);
void conflux_validate_stream_lists(const conflux_t *cfx);
void conflux_validate_legs(const conflux_t *cfx);
#endif /* TOR_CONFLUX_UTIL_H */
@@ -0,0 +1,199 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file congestion_control_common.h
* \brief Public APIs for congestion control
**/
#ifndef TOR_CONGESTION_CONTROL_COMMON_H
#define TOR_CONGESTION_CONTROL_COMMON_H
#include "core/crypto/onion_crypto.h"
#include "core/or/crypt_path_st.h"
#include "core/or/circuit_st.h"
/* The maximum whole number of cells that can fit in a
* full TLS record. This is 31. */
#define TLS_RECORD_MAX_CELLS ((16 * 1024) / CELL_MAX_NETWORK_SIZE)
typedef struct congestion_control_t congestion_control_t;
/**
* Specifies the path type to help choose congestion control
* parameters. Since these paths are different lengths, they
* will need different queue parameters. */
typedef enum {
CC_PATH_EXIT = 0,
CC_PATH_ONION = 1,
CC_PATH_ONION_SOS = 2,
CC_PATH_ONION_VG = 3,
CC_PATH_SBWS = 4,
} cc_path_t;
/** The length of a path for sbws measurement */
#define SBWS_ROUTE_LEN 2
/** Wrapper for the free function, set the CC pointer to NULL after free */
#define congestion_control_free(cc) \
FREE_AND_NULL(congestion_control_t, congestion_control_free_, cc)
void congestion_control_free_(congestion_control_t *cc);
struct circuit_params_t;
congestion_control_t *congestion_control_new(
const struct circuit_params_t *params,
cc_path_t path);
int congestion_control_dispatch_cc_alg(congestion_control_t *cc,
circuit_t *circ);
void congestion_control_note_cell_sent(congestion_control_t *cc,
const circuit_t *circ,
const crypt_path_t *cpath);
bool congestion_control_update_circuit_estimates(congestion_control_t *,
const circuit_t *);
int congestion_control_get_package_window(const circuit_t *,
const crypt_path_t *);
int sendme_get_inc_count(const circuit_t *, const crypt_path_t *);
bool circuit_sent_cell_for_sendme(const circuit_t *, const crypt_path_t *);
bool is_monotime_clock_reliable(void);
void congestion_control_new_consensus_params(const networkstatus_t *ns);
bool congestion_control_enabled(void);
int congestion_control_build_ext_request(uint8_t **msg_out,
size_t *msg_len_out);
int congestion_control_parse_ext_request(const uint8_t *msg,
const size_t msg_len);
int congestion_control_build_ext_response(const circuit_params_t *our_params,
const circuit_params_t *circ_params,
uint8_t **msg_out,
size_t *msg_len_out);
int congestion_control_parse_ext_response(const uint8_t *msg,
const size_t msg_len,
circuit_params_t *params_out);
bool congestion_control_validate_sendme_increment(uint8_t sendme_inc);
char *congestion_control_get_control_port_fields(const origin_circuit_t *);
uint64_t congestion_control_get_num_rtt_reset(void);
uint64_t congestion_control_get_num_clock_stalls(void);
extern uint64_t cc_stats_circs_created;
/* Ugh, C.. these are private. Use the getter instead, when
* external to the congestion control code. */
extern uint32_t or_conn_highwater;
extern uint32_t or_conn_lowwater;
extern int32_t cell_queue_high;
extern int32_t cell_queue_low;
extern uint8_t cc_sendme_inc;
/** Stop writing on an orconn when its outbuf is this large */
static inline uint32_t
or_conn_highwatermark(void)
{
return or_conn_highwater;
}
/** Resume writing on an orconn when its outbuf is less than this */
static inline uint32_t
or_conn_lowwatermark(void)
{
return or_conn_lowwater;
}
/** Stop reading on edge connections when we have this many cells
* waiting on the appropriate queue. */
static inline int32_t
cell_queue_highwatermark(void)
{
return cell_queue_high;
}
/** Start reading from edge connections again when we get down to this many
* cells. */
static inline int32_t
cell_queue_lowwatermark(void)
{
return cell_queue_low;
}
/** Returns the sendme inc rate cached from the most recent consensus */
static inline uint8_t
congestion_control_sendme_inc(void)
{
return cc_sendme_inc;
}
/**
* Compute an N-count EWMA, aka N-EWMA. N-EWMA is defined as:
* EWMA = alpha*value + (1-alpha)*EWMA_prev
* with alpha = 2/(N+1).
*
* This works out to:
* EWMA = value*2/(N+1) + EMA_prev*(N-1)/(N+1)
* = (value*2 + EWMA_prev*(N-1))/(N+1)
*/
static inline uint64_t
n_count_ewma(uint64_t curr, uint64_t prev, uint64_t N)
{
if (prev == 0)
return curr;
else
return (2*curr + (N-1)*prev)/(N+1);
}
/**
* Helper function that gives us a percentile weighted-average between
* two values. The pct_max argument specifies the percentage weight of the
* maximum of a and b, when computing this weighted-average.
*
* This also allows this function to be used as either MIN() or a MAX()
* by this parameterization. It is MIN() when pct_max==0;
* it is MAX() when pct_max==100; it is avg() when pct_max==50; it is a
* weighted-average for values in between.
*/
static inline uint64_t
percent_max_mix(uint64_t a, uint64_t b, uint8_t pct_max)
{
uint64_t max = MAX(a, b);
uint64_t min = MIN(a, b);
if (BUG(pct_max > 100)) {
return max;
}
return pct_max*max/100 + (100-pct_max)*min/100;
}
/* Private section starts. */
#ifdef TOR_CONGESTION_CONTROL_COMMON_PRIVATE
STATIC uint64_t congestion_control_update_circuit_rtt(congestion_control_t *,
uint64_t);
STATIC bool time_delta_stalled_or_jumped(const congestion_control_t *cc,
uint64_t old_delta, uint64_t new_delta);
STATIC void enqueue_timestamp(smartlist_t *timestamps_u64,
uint64_t timestamp_usec);
/*
* Unit tests declaractions.
*/
#ifdef TOR_UNIT_TESTS
extern bool is_monotime_clock_broken;
extern cc_alg_t cc_alg;
void congestion_control_set_cc_enabled(void);
void congestion_control_set_cc_disabled(void);
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(TOR_CONGESTION_CONTROL_PRIVATE) */
#endif /* !defined(TOR_CONGESTION_CONTROL_COMMON_H) */
@@ -0,0 +1,52 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file congestion_control_flow.h
* \brief APIs for stream flow control on congestion controlled circuits.
**/
#ifndef TOR_CONGESTION_CONTROL_FLOW_H
#define TOR_CONGESTION_CONTROL_FLOW_H
#include "core/or/crypt_path_st.h"
#include "core/or/circuit_st.h"
#include "core/or/edge_connection_st.h"
void flow_control_new_consensus_params(const struct networkstatus_t *);
bool circuit_process_stream_xoff(edge_connection_t *conn,
const crypt_path_t *layer_hint,
const cell_t *cell);
bool circuit_process_stream_xon(edge_connection_t *conn,
const crypt_path_t *layer_hint,
const cell_t *cell);
int flow_control_decide_xoff(edge_connection_t *stream);
void flow_control_decide_xon(edge_connection_t *stream, size_t n_written);
void flow_control_note_sent_data(edge_connection_t *stream, size_t len);
bool edge_uses_flow_control(const edge_connection_t *stream);
bool conn_uses_flow_control(connection_t *stream);
/** Metricsport externs */
extern uint64_t cc_stats_flow_num_xoff_sent;
extern uint64_t cc_stats_flow_num_xon_sent;
extern double cc_stats_flow_xoff_outbuf_ma;
extern double cc_stats_flow_xon_outbuf_ma;
/* Private section starts. */
#ifdef TOR_CONGESTION_CONTROL_FLOW_PRIVATE
/*
* Unit tests declaractions.
*/
#ifdef TOR_UNIT_TESTS
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(TOR_CONGESTION_CONTROL_FLOW_PRIVATE) */
#endif /* !defined(TOR_CONGESTION_CONTROL_FLOW_H) */
@@ -0,0 +1,242 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file congestion_control_st.h
* \brief Structure definitions for congestion control.
**/
#ifndef CONGESTION_CONTROL_ST_H
#define CONGESTION_CONTROL_ST_H
#include "core/or/crypt_path_st.h"
#include "core/or/circuit_st.h"
/** Signifies which sendme algorithm to use */
typedef enum {
/** OG Tor fixed-sized circ and stream windows. It sucks, but it is important
* to make sure that the new algs can compete with the old garbage. */
CC_ALG_SENDME = 0,
/**
* Prop#324 TOR_WESTWOOD - Deliberately aggressive. Westwood may not even
* converge to fairness in some cases because max RTT will also increase
* on congestion, which boosts the Westwood RTT congestion threshold. So it
* can cause runaway queue bloat, which may or may not lead to a robot
* uprising... Ok that's Westworld, not Westwood. Still, we need to test
* Vegas and NOLA against something more aggressive to ensure they do not
* starve in the presence of cheaters. We also need to make sure cheaters
* trigger the oomkiller in those cases.
*/
CC_ALG_WESTWOOD = 1,
/**
* Prop#324 TOR_VEGAS - TCP Vegas-style BDP tracker. Because Vegas backs off
* whenever it detects queue delay, it can be beaten out by more aggressive
* algs. However, in live network testing, it seems to do just fine against
* current SENDMEs. It outperforms Westwood and does not stall. */
CC_ALG_VEGAS = 2,
/**
* Prop#324: TOR_NOLA - NOLA looks the BDP right in the eye and uses it
* immediately as CWND. No slow start, no other congestion signals, no delay,
* no bullshit. Like TOR_VEGAS, it also uses aggressive BDP estimates, to
* avoid out-competition. It seems a bit better throughput than Vegas, but
* its aggressive BDP and rapid updates may lead to more queue latency. */
CC_ALG_NOLA = 3,
} cc_alg_t;
/* Total number of CC algs in cc_alg_t enum */
#define NUM_CC_ALGS (CC_ALG_NOLA+1)
/** Signifies how we estimate circuit BDP */
typedef enum {
/* CWND-based BDP will respond to changes in RTT only, and is relative
* to cwnd growth. So in slow-start, this will under-estimate BDP */
BDP_ALG_CWND_RTT = 0,
/* Sendme-based BDP will quickly measure BDP in less than
* a cwnd worth of data when in use. So it should be good for slow-start.
* But if the link goes idle, it will be vastly lower than true BDP. Thus,
* this estimate gets reset when the cwnd is not fully utilized. */
BDP_ALG_SENDME_RATE = 1,
/* Inflight BDP is similar to the cwnd estimator, except it uses
* packets inflight minus local circuit queues instead of current cwnd.
* Because it is strictly less than or equal to the cwnd, it will cause
* the cwnd to drift downward. It is only used if the local OR connection
* is blocked. */
BDP_ALG_INFLIGHT_RTT = 2,
/* The Piecewise BDP estimator uses the CWND estimator before there
* are sufficient SENDMEs to calculate the SENDME estimator. At that
* point, it uses the SENDME estimator, unless the local OR connection
* becomes blocked. In that case, it switches to the inflight estimator. */
BDP_ALG_PIECEWISE = 3,
} bdp_alg_t;
/** Total number of BDP algs in bdp_alg_t enum */
#define NUM_BDP_ALGS (BDP_ALG_PIECEWISE+1)
/** Vegas algorithm parameters. */
struct vegas_params_t {
/** The slow-start cwnd cap for RFC3742 */
uint32_t ss_cwnd_cap;
/** The maximum slow-start cwnd */
uint32_t ss_cwnd_max;
/** The queue use allowed before we exit slow start */
uint16_t gamma;
/** The queue use below which we increment cwnd */
uint16_t alpha;
/** The queue use above which we decrement cwnd */
uint16_t beta;
/** The queue use at which we cap cwnd in steady state */
uint16_t delta;
/** Weighted average (percent) between cwnd estimator and
* piecewise estimator. */
uint8_t bdp_mix_pct;
};
/** Fields common to all congestion control algorithms */
struct congestion_control_t {
/**
* Smartlist of uint64_t monotime usec timestamps of when we sent a data
* cell that is pending a sendme. FIFO queue that is managed similar to
* sendme_last_digests. */
smartlist_t *sendme_pending_timestamps;
/** RTT time data for congestion control. */
uint64_t ewma_rtt_usec;
uint64_t min_rtt_usec;
uint64_t max_rtt_usec;
/* Vegas BDP estimate */
uint64_t bdp;
/** Congestion window */
uint64_t cwnd;
/** Number of cells in-flight (sent but awaiting SENDME ack). */
uint64_t inflight;
/**
* For steady-state: the number of sendme acks until we will acknowledge
* a congestion event again. It starts out as the number of sendme acks
* in a congestion window and is decremented each ack. When this reaches
* 0, it means we should examine our congestion algorithm conditions.
* In this way, we only react to one congestion event per congestion window.
*
* It is also reset to 0 immediately whenever the circuit's orconn is
* blocked, and when a previously blocked orconn is unblocked.
*/
uint16_t next_cc_event;
/** Counts down until we process a cwnd worth of SENDME acks.
* Used to track full cwnd status. */
uint16_t next_cwnd_event;
/** Are we in slow start? */
bool in_slow_start;
/** Has the cwnd become full since last cwnd update? */
bool cwnd_full;
/** Is the local channel blocked on us? That's a congestion signal */
bool blocked_chan;
/* The following parameters are cached from consensus values upon
* circuit setup. */
/** Percent of cwnd to increment by during slow start */
uint16_t cwnd_inc_pct_ss;
/** Number of cells to increment cwnd by during steady state */
uint16_t cwnd_inc;
/** Minimum congestion window (must be at least sendme_inc) */
uint16_t cwnd_min;
/**
* Number of times per congestion window to update based on congestion
* signals */
uint8_t cwnd_inc_rate;
/**
* Number of cells to ack with every sendme. Taken from consensus parameter
* and negotiation during circuit setup. */
uint8_t sendme_inc;
/** Which congestion control algorithm to use. Taken from
* consensus parameter and negotiation during circuit setup. */
cc_alg_t cc_alg;
/** Which algorithm to estimate circuit bandwidth with. Taken from
* consensus parameter during circuit setup. */
bdp_alg_t bdp_alg;
/** Vegas-specific parameters. These should not be accessed anywhere
* other than the congestion_control_vegas.c file. */
struct vegas_params_t vegas_params;
};
/**
* Returns the number of sendme acks we will receive before we update cwnd.
*
* Congestion control literature recommends only one update of cwnd per
* cwnd worth of acks. However, we can also tune this to be more frequent
* by increasing the 'cc_cwnd_inc_rate' consensus parameter. This tuning
* only applies after slow start.
*
* If this returns 0 due to high cwnd_inc_rate, the calling code will
* update every sendme ack.
*/
static inline uint64_t CWND_UPDATE_RATE(const struct congestion_control_t *cc)
{
/* We add cwnd_inc_rate*sendme_inc/2 to round to nearest integer number
* of acks */
if (cc->in_slow_start) {
return 1;
} else {
return ((cc->cwnd + cc->cwnd_inc_rate*cc->sendme_inc/2)
/ (cc->cwnd_inc_rate*cc->sendme_inc));
}
}
/**
* Gives us the number of SENDMEs in a CWND, rounded.
*/
static inline uint64_t SENDME_PER_CWND(const struct congestion_control_t *cc)
{
/* We add cwnd_inc_rate*sendme_inc/2 to round to nearest integer number
* of acks */
return ((cc->cwnd + cc->sendme_inc/2)/cc->sendme_inc);
}
/**
* Returns the amount to increment the congestion window each update,
* during slow start.
*
* Congestion control literature recommends either doubling the cwnd
* every cwnd during slow start, or some similar exponential growth
* (such as 50% more every cwnd, for Vegas).
*
* This is controlled by a consensus parameter 'cwnd_inc_pct_ss', which
* allows us to specify the percent of the current consensus window
* to update by.
*/
static inline uint64_t CWND_INC_SS(const struct congestion_control_t *cc)
{
return (cc->cwnd_inc_pct_ss*cc->cwnd/100);
}
/**
* Returns the amount to increment (and for Vegas, also decrement) the
* congestion window by, every update period.
*
* This is controlled by the cc_cwnd_inc consensus parameter.
*/
#define CWND_INC(cc) ((cc)->cwnd_inc)
#endif /* !defined(CONGESTION_CONTROL_ST_H) */
@@ -0,0 +1,54 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file congestion_control_vegas.h
* \brief Private-ish APIs for the TOR_VEGAS congestion control algorithm
**/
#ifndef TOR_CONGESTION_CONTROL_VEGAS_H
#define TOR_CONGESTION_CONTROL_VEGAS_H
#include "core/or/crypt_path_st.h"
#include "core/or/circuit_st.h"
extern double cc_stats_vegas_exit_ss_cwnd_ma;
extern double cc_stats_vegas_exit_ss_bdp_ma;
extern double cc_stats_vegas_exit_ss_inc_ma;
extern double cc_stats_vegas_gamma_drop_ma;
extern double cc_stats_vegas_delta_drop_ma;
extern double cc_stats_vegas_ss_csig_blocked_ma;
extern double cc_stats_vegas_csig_blocked_ma;
extern uint64_t cc_stats_vegas_above_delta;
extern uint64_t cc_stats_vegas_above_ss_cwnd_max;
extern double cc_stats_vegas_csig_alpha_ma;
extern double cc_stats_vegas_csig_beta_ma;
extern double cc_stats_vegas_csig_delta_ma;
extern double cc_stats_vegas_ss_queue_ma;
extern double cc_stats_vegas_queue_ma;
extern double cc_stats_vegas_bdp_ma;
extern uint64_t cc_stats_vegas_below_ss_inc_floor;
extern uint64_t cc_stats_vegas_circ_exited_ss;
/* Processing SENDME cell. */
int congestion_control_vegas_process_sendme(struct congestion_control_t *cc,
const circuit_t *circ);
void congestion_control_vegas_set_params(struct congestion_control_t *cc,
cc_path_t path);
/* Private section starts. */
#ifdef TOR_CONGESTION_CONTROL_VEGAS_PRIVATE
/*
* Unit tests declaractions.
*/
#ifdef TOR_UNIT_TESTS
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(TOR_CONGESTION_CONTROL_VEGAS_PRIVATE) */
#endif /* !defined(TOR_CONGESTION_CONTROL_VEGAS_H) */
@@ -0,0 +1,311 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file connection_edge.h
* \brief Header file for connection_edge.c.
**/
#ifndef TOR_CONNECTION_EDGE_H
#define TOR_CONNECTION_EDGE_H
#include "lib/testsupport/testsupport.h"
#include "feature/hs/hs_service.h"
edge_connection_t *TO_EDGE_CONN(connection_t *);
entry_connection_t *TO_ENTRY_CONN(connection_t *);
entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);
const edge_connection_t *CONST_TO_EDGE_CONN(const connection_t *);
const entry_connection_t *CONST_TO_ENTRY_CONN(const connection_t *);
const entry_connection_t *CONST_EDGE_TO_ENTRY_CONN(const edge_connection_t *);
#define EXIT_CONN_STATE_MIN_ 1
/** State for an exit connection: waiting for response from DNS farm. */
#define EXIT_CONN_STATE_RESOLVING 1
/** State for an exit connection: waiting for connect() to finish. */
#define EXIT_CONN_STATE_CONNECTING 2
/** State for an exit connection: open and ready to transmit data. */
#define EXIT_CONN_STATE_OPEN 3
/** State for an exit connection: waiting to be removed. */
#define EXIT_CONN_STATE_RESOLVEFAILED 4
#define EXIT_CONN_STATE_MAX_ 4
/* The AP state values must be disjoint from the EXIT state values. */
#define AP_CONN_STATE_MIN_ 5
/** State for a SOCKS connection: waiting for SOCKS request. */
#define AP_CONN_STATE_SOCKS_WAIT 5
/** State for a SOCKS connection: got a y.onion URL; waiting to receive
* rendezvous descriptor. */
#define AP_CONN_STATE_RENDDESC_WAIT 6
/** The controller will attach this connection to a circuit; it isn't our
* job to do so. */
#define AP_CONN_STATE_CONTROLLER_WAIT 7
/** State for a SOCKS connection: waiting for a completed circuit. */
#define AP_CONN_STATE_CIRCUIT_WAIT 8
/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */
#define AP_CONN_STATE_CONNECT_WAIT 9
/** State for a SOCKS connection: sent RESOLVE, waiting for RESOLVED. */
#define AP_CONN_STATE_RESOLVE_WAIT 10
/** State for a SOCKS connection: ready to send and receive. */
#define AP_CONN_STATE_OPEN 11
/** State for a transparent natd connection: waiting for original
* destination. */
#define AP_CONN_STATE_NATD_WAIT 12
/** State for an HTTP tunnel: waiting for an HTTP CONNECT command. */
#define AP_CONN_STATE_HTTP_CONNECT_WAIT 13
#define AP_CONN_STATE_MAX_ 13
#define EXIT_PURPOSE_MIN_ 1
/** This exit stream wants to do an ordinary connect. */
#define EXIT_PURPOSE_CONNECT 1
/** This exit stream wants to do a resolve (either normal or reverse). */
#define EXIT_PURPOSE_RESOLVE 2
#define EXIT_PURPOSE_MAX_ 2
/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding
* edge connection is not attached to any circuit. */
#define AP_CONN_STATE_IS_UNATTACHED(s) \
((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT)
#define connection_mark_unattached_ap(conn, endreason) \
connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)
/** Possible return values for parse_extended_hostname. */
typedef enum hostname_type_t {
BAD_HOSTNAME,
EXIT_HOSTNAME,
NORMAL_HOSTNAME,
ONION_V3_HOSTNAME,
} hostname_type_t;
MOCK_DECL(void,connection_mark_unattached_ap_,
(entry_connection_t *conn, int endreason,
int line, const char *file));
int connection_edge_reached_eof(edge_connection_t *conn);
int connection_edge_process_inbuf(edge_connection_t *conn,
int package_partial);
int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn);
int connection_edge_end(edge_connection_t *conn, uint8_t reason);
int connection_edge_end_errno(edge_connection_t *conn);
void connection_edge_end_close(edge_connection_t *conn, uint8_t reason);
int connection_edge_flushed_some(edge_connection_t *conn);
int connection_edge_finished_flushing(edge_connection_t *conn);
int connection_edge_finished_connecting(edge_connection_t *conn);
void connection_entry_set_controller_wait(entry_connection_t *conn);
void connection_ap_about_to_close(entry_connection_t *edge_conn);
void connection_exit_about_to_close(edge_connection_t *edge_conn);
MOCK_DECL(int,
connection_ap_handshake_send_begin,(entry_connection_t *ap_conn));
int connection_ap_handshake_send_resolve(entry_connection_t *ap_conn);
entry_connection_t *connection_ap_make_link(connection_t *partner,
char *address, uint16_t port,
const char *digest,
int session_group,
int isolation_flags,
int use_begindir, int want_onehop);
void connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
size_t replylen,
int endreason);
MOCK_DECL(void,connection_ap_handshake_socks_resolved,
(entry_connection_t *conn,
int answer_type,
size_t answer_len,
const uint8_t *answer,
int ttl,
time_t expires));
void connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn,
const tor_addr_t *answer,
int ttl,
time_t expires);
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
void connection_exit_connect(edge_connection_t *conn);
int connection_edge_is_rendezvous_stream(const edge_connection_t *conn);
int connection_ap_can_use_exit(const entry_connection_t *conn,
const node_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_rescan_and_attach_pending(void);
void connection_ap_attach_pending(int retry);
void connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
const char *file, int line);
#define connection_ap_mark_as_pending_circuit(c) \
connection_ap_mark_as_pending_circuit_((c), __FILE__, __LINE__)
void connection_ap_mark_as_non_pending_circuit(entry_connection_t *entry_conn);
void connection_ap_mark_as_waiting_for_renddesc(
entry_connection_t *entry_conn);
#define CONNECTION_AP_EXPECT_NONPENDING(c) do { \
if (ENTRY_TO_CONN(c)->state == AP_CONN_STATE_CIRCUIT_WAIT) { \
log_warn(LD_BUG, "At %s:%d: %p was unexpectedly in circuit_wait.", \
__FILE__, __LINE__, (c)); \
connection_ap_mark_as_non_pending_circuit(c); \
} \
} while (0)
void connection_ap_fail_onehop(const char *failed_digest,
cpath_build_state_t *build_state);
void circuit_discard_optional_exit_enclaves(extend_info_t *info);
int connection_ap_detach_retriable(entry_connection_t *conn,
origin_circuit_t *circ,
int reason);
int connection_ap_process_transparent(entry_connection_t *conn);
int address_is_invalid_destination(const char *address, int client);
MOCK_DECL(int, connection_ap_rewrite_and_attach_if_allowed,
(entry_connection_t *conn,
origin_circuit_t *circ,
crypt_path_t *cpath));
int connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
origin_circuit_t *circ,
crypt_path_t *cpath);
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
int get_pf_socket(void);
#endif
int connection_edge_compatible_with_circuit(const entry_connection_t *conn,
const origin_circuit_t *circ);
int connection_edge_update_circuit_isolation(const entry_connection_t *conn,
origin_circuit_t *circ,
int dry_run);
void circuit_clear_isolation(origin_circuit_t *circ);
streamid_t get_unique_stream_id_by_circ(origin_circuit_t *circ);
void connection_edge_free_all(void);
void connection_ap_warn_and_unmark_if_pending_circ(
entry_connection_t *entry_conn,
const char *where);
/** Lowest value for DNS ttl clipping excluding the random addition. */
#define MIN_DNS_TTL (5*60)
/** Highest value for DNS ttl clipping excluding the random addition. */
#define MAX_DNS_TTL (60*60)
/** How long do we keep DNS cache entries before purging them (regardless of
* their TTL)? */
#define MAX_DNS_ENTRY_AGE (3*60*60)
/** How long do we cache/tell clients to cache DNS records when no TTL is
* known? */
#define DEFAULT_DNS_TTL (30*60)
/** How much should we +- each TTL to make it fuzzy with uniform sampling at
* exits? The value 4 minutes was chosen so that the lowest possible clip is
* 60s. Such low clips were used in the past for all TTLs due to a bug in Tor,
* see "The effect of DNS on Tor's Anonymity" by Greschbach et al. In other
* words, sampling such low clips is unlikely to cause any breakage at exits.
*/
#define FUZZY_DNS_TTL (4*60)
uint32_t clip_dns_ttl(uint32_t ttl);
uint32_t clip_dns_fuzzy_ttl(uint32_t ttl);
int connection_half_edge_is_valid_data(const smartlist_t *half_conns,
streamid_t stream_id);
int connection_half_edge_is_valid_sendme(const smartlist_t *half_conns,
streamid_t stream_id);
int connection_half_edge_is_valid_connected(const smartlist_t *half_conns,
streamid_t stream_id);
int connection_half_edge_is_valid_end(smartlist_t *half_conns,
streamid_t stream_id);
int connection_half_edge_is_valid_resolved(smartlist_t *half_conns,
streamid_t stream_id);
bool connection_half_edges_waiting(const origin_circuit_t *circ);
size_t half_streams_get_total_allocation(void);
struct half_edge_t;
void half_edge_free_(struct half_edge_t *he);
#define half_edge_free(he) \
FREE_AND_NULL(half_edge_t, half_edge_free_, (he))
/** @name Begin-cell flags
*
* These flags are used in RELAY_BEGIN cells to change the default behavior
* of the cell.
*
* @{
**/
/** When this flag is set, the client is willing to get connected to IPv6
* addresses */
#define BEGIN_FLAG_IPV6_OK (1u<<0)
/** When this flag is set, the client DOES NOT support connecting to IPv4
* addresses. (The sense of this flag is inverted from IPV6_OK, so that the
* old default behavior of Tor is equivalent to having all flags set to 0.)
**/
#define BEGIN_FLAG_IPV4_NOT_OK (1u<<1)
/** When this flag is set, if we find both an IPv4 and an IPv6 address,
* we use the IPv6 address. Otherwise we use the IPv4 address. */
#define BEGIN_FLAG_IPV6_PREFERRED (1u<<2)
/**@}*/
#ifdef CONNECTION_EDGE_PRIVATE
STATIC bool parse_extended_hostname(char *address, hostname_type_t *type_out);
/** A parsed BEGIN or BEGIN_DIR cell */
typedef struct begin_cell_t {
/** The address the client has asked us to connect to, or NULL if this is
* a BEGIN_DIR cell*/
char *address;
/** The flags specified in the BEGIN cell's body. One or more of
* BEGIN_FLAG_*. */
uint32_t flags;
/** The client's requested port. */
uint16_t port;
/** The client's requested Stream ID */
uint16_t stream_id;
/** True iff this is a BEGIN_DIR cell. */
unsigned is_begindir : 1;
} begin_cell_t;
STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out);
STATIC int connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl);
typedef struct {
/** Original address, after we lowercased it but before we started
* mapping it.
*/
char orig_address[MAX_SOCKS_ADDR_LEN];
/** True iff the address has been automatically remapped to a local
* address in VirtualAddrNetwork. (Only set true when we do a resolve
* and get a virtual address; not when we connect to the address.) */
int automap;
/** If this connection has a .exit address, who put it there? */
addressmap_entry_source_t exit_source;
/** If we've rewritten the address, when does this map expire? */
time_t map_expires;
/** If we should close the connection, this is the end_reason to pass
* to connection_mark_unattached_ap */
int end_reason;
/** True iff we should close the connection, either because of error or
* because of successful early RESOLVED reply. */
int should_close;
} rewrite_result_t;
STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn,
rewrite_result_t *out);
STATIC int connection_ap_process_http_connect(entry_connection_t *conn);
STATIC void export_hs_client_circuit_id(edge_connection_t *edge_conn,
hs_circuit_id_protocol_t protocol);
struct half_edge_t;
STATIC void connection_half_edge_add(const edge_connection_t *conn,
origin_circuit_t *circ);
STATIC struct half_edge_t *connection_half_edge_find_stream_id(
const smartlist_t *half_conns,
streamid_t stream_id);
#endif /* defined(CONNECTION_EDGE_PRIVATE) */
#endif /* !defined(TOR_CONNECTION_EDGE_H) */
@@ -0,0 +1,136 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file connection_or.h
* \brief Header file for connection_or.c.
**/
#ifndef TOR_CONNECTION_OR_H
#define TOR_CONNECTION_OR_H
struct ed25519_public_key_t;
struct ed25519_keypair_t;
or_connection_t *TO_OR_CONN(connection_t *);
const or_connection_t *CONST_TO_OR_CONN(const connection_t *);
#include "core/or/orconn_event.h"
void connection_or_clear_identity(or_connection_t *conn);
void connection_or_clear_identity_map(void);
void clear_broken_connection_map(int disable);
void connection_or_block_renegotiation(or_connection_t *conn);
int connection_or_reached_eof(or_connection_t *conn);
int connection_or_process_inbuf(or_connection_t *conn);
ssize_t connection_or_num_cells_writeable(or_connection_t *conn);
int connection_or_flushed_some(or_connection_t *conn);
int connection_or_finished_flushing(or_connection_t *conn);
int connection_or_finished_connecting(or_connection_t *conn);
void connection_or_about_to_close(or_connection_t *conn);
int connection_or_digest_is_known_relay(const char *id_digest);
void connection_or_update_token_buckets(smartlist_t *conns,
const or_options_t *options);
void connection_or_connect_failed(or_connection_t *conn,
int reason, const char *msg);
void connection_or_notify_error(or_connection_t *conn,
int reason, const char *msg);
MOCK_DECL(or_connection_t *,
connection_or_connect,
(const tor_addr_t *addr, uint16_t port,
const char *id_digest,
const struct ed25519_public_key_t *ed_id,
channel_tls_t *chan));
void connection_or_close_normally(or_connection_t *orconn, int flush);
MOCK_DECL(void,connection_or_close_for_error,
(or_connection_t *orconn, int flush));
void connection_or_report_broken_states(int severity, int domain);
void connection_or_event_status(or_connection_t *conn,
or_conn_status_event_t tp, int reason);
MOCK_DECL(int,connection_tls_start_handshake,(or_connection_t *conn,
int receiving));
int connection_tls_continue_handshake(or_connection_t *conn);
void connection_or_set_canonical(or_connection_t *or_conn,
int is_canonical);
int connection_init_or_handshake_state(or_connection_t *conn,
int started_here);
void connection_or_init_conn_from_address(or_connection_t *conn,
const tor_addr_t *addr,
uint16_t port,
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
int started_here);
int connection_or_client_learned_peer_id(or_connection_t *conn,
const uint8_t *rsa_peer_id,
const struct ed25519_public_key_t *ed_peer_id);
const struct ed25519_public_key_t *connection_or_get_alleged_ed25519_id(
const or_connection_t *conn);
time_t connection_or_client_used(or_connection_t *conn);
MOCK_DECL(int, connection_or_get_num_circuits, (or_connection_t *conn));
void or_handshake_state_free_(or_handshake_state_t *state);
#define or_handshake_state_free(state) \
FREE_AND_NULL(or_handshake_state_t, or_handshake_state_free_, (state))
void or_handshake_state_record_cell(or_connection_t *conn,
or_handshake_state_t *state,
const cell_t *cell,
int incoming);
void or_handshake_state_record_var_cell(or_connection_t *conn,
or_handshake_state_t *state,
const var_cell_t *cell,
int incoming);
int connection_or_set_state_open(or_connection_t *conn);
void connection_or_write_cell_to_buf(const cell_t *cell,
or_connection_t *conn);
MOCK_DECL(void,connection_or_write_var_cell_to_buf,(const var_cell_t *cell,
or_connection_t *conn));
int connection_or_send_versions(or_connection_t *conn, int v3_plus);
MOCK_DECL(int,connection_or_send_netinfo,(or_connection_t *conn));
int is_or_protocol_version_known(uint16_t version);
void cell_pack(packed_cell_t *dest, const cell_t *src, int wide_circ_ids);
int var_cell_pack_header(const var_cell_t *cell, char *hdr_out,
int wide_circ_ids);
var_cell_t *var_cell_new(uint16_t payload_len);
var_cell_t *var_cell_copy(const var_cell_t *src);
void var_cell_free_(var_cell_t *cell);
#define var_cell_free(cell) FREE_AND_NULL(var_cell_t, var_cell_free_, (cell))
/* DOCDOC */
#define MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS 4
#define MIN_LINK_PROTO_FOR_CHANNEL_PADDING 5
#define MAX_LINK_PROTO MIN_LINK_PROTO_FOR_CHANNEL_PADDING
int connection_or_single_set_badness_(time_t now,
or_connection_t *or_conn,
int force);
void connection_or_group_set_badness_(smartlist_t *group, int force);
#ifdef CONNECTION_OR_PRIVATE
STATIC int should_connect_to_relay(const or_connection_t *or_conn);
STATIC void note_or_connect_failed(const or_connection_t *or_conn);
#endif /* defined(CONNECTION_OR_PRIVATE) */
/*
* Call this when changing connection state, so notifications to the owning
* channel can be handled.
*/
MOCK_DECL(void, connection_or_change_state,
(or_connection_t *conn, uint8_t state));
#ifdef TOR_UNIT_TESTS
extern int testing__connection_or_pretend_TLSSECRET_is_supported;
#endif
#endif /* !defined(TOR_CONNECTION_OR_H) */
@@ -0,0 +1,194 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file connection_st.h
* @brief Base connection structure.
**/
#ifndef CONNECTION_ST_H
#define CONNECTION_ST_H
struct buf_t;
/* Values for connection_t.magic: used to make sure that downcasts (casts from
* connection_t to foo_connection_t) are safe. */
#define BASE_CONNECTION_MAGIC 0x7C3C304Eu
#define OR_CONNECTION_MAGIC 0x7D31FF03u
#define EDGE_CONNECTION_MAGIC 0xF0374013u
#define ENTRY_CONNECTION_MAGIC 0xbb4a5703
#define DIR_CONNECTION_MAGIC 0x9988ffeeu
#define CONTROL_CONNECTION_MAGIC 0x8abc765du
#define LISTENER_CONNECTION_MAGIC 0x1a1ac741u
/** Description of a connection to another host or process, and associated
* data.
*
* A connection is named based on what it's connected to -- an "OR
* connection" has a Tor node on the other end, an "exit
* connection" has a website or other server on the other end, and an
* "AP connection" has an application proxy (and thus a user) on the
* other end.
*
* Every connection has a type and a state. Connections never change
* their type, but can go through many state changes in their lifetime.
*
* Every connection has two associated input and output buffers.
* Listeners don't use them. For non-listener connections, incoming
* data is appended to conn->inbuf, and outgoing data is taken from
* conn->outbuf. Connections differ primarily in the functions called
* to fill and drain these buffers.
*/
struct connection_t {
uint32_t magic; /**< For memory debugging: must equal one of
* *_CONNECTION_MAGIC. */
uint8_t state; /**< Current state of this connection. */
unsigned int type:5; /**< What kind of connection is this? */
unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */
/* The next fields are all one-bit booleans. Some are only applicable to
* connection subtypes, but we hold them here anyway, to save space.
*/
unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading
* again once the bandwidth throttler allows it? */
unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing
* again once the bandwidth throttler allows
* writes? */
unsigned int hold_open_until_flushed:1; /**< Despite this connection's being
* marked for close, do we flush it
* before closing it? */
unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this
* conn? */
/** Set to 1 when we're inside connection_flushed_some to keep us from
* calling connection_handle_write() recursively. */
unsigned int in_flushed_some:1;
/** True if connection_handle_write is currently running on this connection.
*/
unsigned int in_connection_handle_write:1;
/** If true, then we treat this connection as remote for the purpose of
* rate-limiting, no matter what its address is. */
unsigned int always_rate_limit_as_remote:1;
/* For linked connections:
*/
unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */
/** True iff we'd like to be notified about read events from the
* linked conn. */
unsigned int reading_from_linked_conn:1;
/** True iff we're willing to write to the linked conn. */
unsigned int writing_to_linked_conn:1;
/** True iff we're currently able to read on the linked conn, and our
* read_event should be made active with libevent. */
unsigned int active_on_link:1;
/** True iff we've called connection_close_immediate() on this linked
* connection. */
unsigned int linked_conn_is_closed:1;
/** True iff this connection was opened from a listener and thus we've
* received this connection. Else, it means we've initiated an outbound
* connection. */
unsigned int from_listener:1;
/** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */
unsigned int proxy_state:4;
/** Our socket; set to TOR_INVALID_SOCKET if this connection is closed,
* or has no socket. */
tor_socket_t s;
int conn_array_index; /**< Index into the global connection array. */
struct event *read_event; /**< Libevent event structure. */
struct event *write_event; /**< Libevent event structure. */
struct buf_t *inbuf; /**< Buffer holding data read over this connection. */
struct buf_t *outbuf; /**< Buffer holding data to write over this
* connection. */
time_t timestamp_last_read_allowed; /**< When was the last time libevent said
* we could read? */
time_t timestamp_last_write_allowed; /**< When was the last time libevent
* said we could write? */
time_t timestamp_created; /**< When was this connection_t created? */
int socket_family; /**< Address family of this connection's socket. Usually
* AF_INET, but it can also be AF_UNIX, or AF_INET6 */
/**
* IP address on the internet of this connection's peer, usually.
*
* This address may come from several sources. If this is an outbound
* connection, it is the address we are trying to connect to--either
* directly through `s`, or via a proxy. (If we used a proxy, then
* `getpeername(s)` will not give this address.)
*
* For incoming connections, this field is the address we got from
* getpeername() or accept(), as updated by any proxy that we
* are using (for example, an ExtORPort proxy).
*
* For listeners, this is the address we are trying to bind to.
*
* If this connection is using a unix socket, then this address is a null
* address, and the real address is in the `address` field.
*
* If this connection represents a request made somewhere other than via
* TCP (for example, a UDP dns request, or a controller resolve request),
* then this address is the address that originated the request.
*
* TECHNICAL DEBT:
*
* There are a few places in the code that modify this address,
* or use it in other ways that we don't currently like. Please don't add
* any more!
*
* The misuses of this field include:
* * Setting it on linked connections, possibly.
* * Updating it based on the Forwarded-For header-- Forwarded-For is
* set by a proxy, but not a local trusted proxy.
**/
tor_addr_t addr;
uint16_t port; /**< If non-zero, port that socket "s" is directly connected
* to; may be the port for a proxy or pluggable transport,
* see "address" for the port at the final destination. */
uint16_t marked_for_close; /**< Should we close this conn on the next
* iteration of the main loop? (If true, holds
* the line number where this connection was
* marked.) */
const char *marked_for_close_file; /**< For debugging: in which file were
* we marked for close? */
/**
* String address of the peer of this connection.
*
* TECHNICAL DEBT:
*
* This field serves many purposes, and they're not all pretty. In addition
* to describing the peer we're connected to, it can also hold:
*
* * An address we're trying to resolve (as an exit).
* * A unix address we're trying to bind to (as a listener).
**/
char *address;
/** Another connection that's connected to this one in lieu of a socket. */
struct connection_t *linked_conn;
/** Unique identifier for this connection on this Tor instance. */
uint64_t global_identifier;
/** Bytes read since last call to control_event_conn_bandwidth_used().
* Only used if we're configured to emit CONN_BW events. */
uint32_t n_read_conn_bw;
/** Bytes written since last call to control_event_conn_bandwidth_used().
* Only used if we're configured to emit CONN_BW events. */
uint32_t n_written_conn_bw;
};
/** True iff <b>x</b> is an edge connection. */
#define CONN_IS_EDGE(x) \
((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP)
/** True iff the purpose of <b>conn</b> means that it's a server-side
* directory connection. */
#define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER)
#endif /* !defined(CONNECTION_ST_H) */
@@ -0,0 +1,41 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file cpath_build_state_st.h
* @brief Circuit-build-stse structure
**/
#ifndef CIRCUIT_BUILD_STATE_ST_ST_H
#define CIRCUIT_BUILD_STATE_ST_ST_H
/** Information used to build a circuit. */
struct cpath_build_state_t {
/** Intended length of the final circuit. */
int desired_path_len;
/** How to extend to the planned exit node. */
extend_info_t *chosen_exit;
/** Whether every node in the circ must have adequate uptime. */
unsigned int need_uptime : 1;
/** Whether every node in the circ must have adequate capacity. */
unsigned int need_capacity : 1;
/** Whether the last hop was picked with exiting in mind. */
unsigned int is_internal : 1;
/** Is this an IPv6 ORPort self-testing circuit? */
unsigned int is_ipv6_selftest : 1;
/** Did we pick this as a one-hop tunnel (not safe for other streams)?
* These are for encrypted dir conns that exit to this router, not
* for arbitrary exits from the circuit. */
unsigned int onehop_tunnel : 1;
/** Indicating the exit needs to support Conflux. */
unsigned int need_conflux: 1;
/** How many times has building a circuit for this task failed? */
int failure_count;
/** At what time should we give up on this task? */
time_t expiry_time;
};
#endif /* !defined(CIRCUIT_BUILD_STATE_ST_ST_H) */
@@ -0,0 +1,46 @@
/**
* \file crypt_path.h
* \brief Header file for crypt_path.c.
**/
#ifndef CRYPT_PATH_H
#define CRYPT_PATH_H
void cpath_assert_layer_ok(const crypt_path_t *cp);
void cpath_assert_ok(const crypt_path_t *cp);
int cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
int cpath_init_circuit_crypto(crypt_path_t *cpath,
const char *key_data, size_t key_data_len,
int reverse, int is_hs_v3);
void
cpath_free(crypt_path_t *victim);
void cpath_extend_linked_list(crypt_path_t **head_ptr, crypt_path_t *new_hop);
void
cpath_crypt_cell(const crypt_path_t *cpath, uint8_t *payload, bool is_decrypt);
struct crypto_digest_t *
cpath_get_incoming_digest(const crypt_path_t *cpath);
void cpath_sendme_record_cell_digest(crypt_path_t *cpath,
bool is_foward_digest);
void
cpath_set_cell_forward_digest(crypt_path_t *cpath, cell_t *cell);
crypt_path_t *cpath_get_next_non_open_hop(crypt_path_t *cpath);
void cpath_sendme_circuit_record_inbound_cell(crypt_path_t *cpath);
uint8_t *cpath_get_sendme_digest(crypt_path_t *cpath);
#if defined(TOR_UNIT_TESTS)
unsigned int cpath_get_n_hops(crypt_path_t **head_ptr);
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* !defined(CRYPT_PATH_H) */
@@ -0,0 +1,27 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file crypt_path_reference_st.h
* @brief reference-counting structure for crypt_path_t
**/
#ifndef CRYPT_PATH_REFERENCE_ST_H
#define CRYPT_PATH_REFERENCE_ST_H
/** A reference-counted pointer to a crypt_path_t, used only to share
* the final rendezvous cpath to be used on a service-side rendezvous
* circuit among multiple circuits built in parallel to the same
* destination rendezvous point. */
struct crypt_path_reference_t {
/** The reference count. */
unsigned int refcount;
/** The pointer. Set to NULL when the crypt_path_t is put into use
* on an opened rendezvous circuit. */
crypt_path_t *cpath;
};
#endif /* !defined(CRYPT_PATH_REFERENCE_ST_H) */
@@ -0,0 +1,98 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file crypt_path_st.h
* @brief Path structures for origin circuits.
**/
#ifndef CRYPT_PATH_ST_H
#define CRYPT_PATH_ST_H
#include "core/or/relay_crypto_st.h"
struct crypto_dh_t;
#define CRYPT_PATH_MAGIC 0x70127012u
struct fast_handshake_state_t;
struct ntor_handshake_state_t;
struct crypto_dh_t;
struct onion_handshake_state_t {
/** One of `ONION_HANDSHAKE_TYPE_*`. Determines which member of the union
* is accessible. */
uint16_t tag;
union {
struct fast_handshake_state_t *fast;
struct crypto_dh_t *tap;
struct ntor_handshake_state_t *ntor;
struct ntor3_handshake_state_t *ntor3;
} u;
};
struct congestion_control_t;
/** Macro to encapsulate private members of a struct.
*
* Renames 'x' to 'x_crypt_path_private_field'.
*/
#define CRYPT_PATH_PRIV_FIELD(x) x ## _crypt_path_private_field
#ifdef CRYPT_PATH_PRIVATE
/* Helper macro to access private members of a struct. */
#define pvt_crypto CRYPT_PATH_PRIV_FIELD(crypto)
#endif /* defined(CRYPT_PATH_PRIVATE) */
/** Holds accounting information for a single step in the layered encryption
* performed by a circuit. Used only at the client edge of a circuit. */
struct crypt_path_t {
uint32_t magic;
/** Current state of the handshake as performed with the OR at this
* step. */
onion_handshake_state_t handshake_state;
/** Diffie-hellman handshake state for performing an introduction
* operations */
struct crypto_dh_t *rend_dh_handshake_state;
/** Negotiated key material shared with the OR at this step. */
char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
/** Information to extend to the OR at this step. */
extend_info_t *extend_info;
/** Is the circuit built to this step? Must be one of:
* - CPATH_STATE_CLOSED (The circuit has not been extended to this step)
* - CPATH_STATE_AWAITING_KEYS (We have sent an EXTEND/CREATE to this step
* and not received an EXTENDED/CREATED)
* - CPATH_STATE_OPEN (The circuit has been extended to this step) */
uint8_t state;
#define CPATH_STATE_CLOSED 0
#define CPATH_STATE_AWAITING_KEYS 1
#define CPATH_STATE_OPEN 2
struct crypt_path_t *next; /**< Link to next crypt_path_t in the circuit.
* (The list is circular, so the last node
* links to the first.) */
struct crypt_path_t *prev; /**< Link to previous crypt_path_t in the
* circuit. */
int package_window; /**< How many cells are we allowed to originate ending
* at this step? */
int deliver_window; /**< How many cells are we willing to deliver originating
* at this step? */
/** Congestion control info */
struct congestion_control_t *ccontrol;
/*********************** Private members ****************************/
/** Private member: Cryptographic state used for encrypting and
* authenticating relay cells to and from this hop. */
relay_crypto_t CRYPT_PATH_PRIV_FIELD(crypto);
};
#endif /* !defined(CRYPT_PATH_ST_H) */
@@ -0,0 +1,33 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file destroy_cell_queue_st.h
* @brief Destroy-cell queue structures
**/
#ifndef DESTROY_CELL_QUEUE_ST_H
#define DESTROY_CELL_QUEUE_ST_H
#include "core/or/cell_queue_st.h"
/** A single queued destroy cell. */
struct destroy_cell_t {
TOR_SIMPLEQ_ENTRY(destroy_cell_t) next;
circid_t circid;
uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell
* was inserted */
uint8_t reason;
};
/** A queue of destroy cells on a channel. */
struct destroy_cell_queue_t {
/** Linked list of packed_cell_t */
TOR_SIMPLEQ_HEAD(dcell_simpleq_t, destroy_cell_t) head;
int n; /**< The number of cells in the queue. */
};
#endif /* !defined(DESTROY_CELL_QUEUE_ST_H) */
@@ -0,0 +1,183 @@
/* Copyright (c) 2018-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
* \file dos.h
* \brief Header file for dos.c
*/
#ifndef TOR_DOS_H
#define TOR_DOS_H
#include "core/or/or.h"
#include "lib/evloop/token_bucket.h"
/* Structure that keeps stats of circuit creation per client connection IP. */
typedef struct cc_client_stats_t {
/* Number of allocated circuits remaining for this address. It is
* decremented every time a new circuit is seen for this client address and
* if the count goes to 0, we have a positive detection. */
uint32_t circuit_bucket;
/* When was the last time we've refilled the circuit bucket? This is used to
* know if we need to refill the bucket when a new circuit is seen. It is
* synchronized using approx_time(). */
time_t last_circ_bucket_refill_ts;
/* This client address was detected to be above the circuit creation rate
* and this timestamp indicates until when it should remain marked as
* detected so we can apply a defense for the address. It is synchronized
* using the approx_time(). */
time_t marked_until_ts;
} cc_client_stats_t;
/* Structure that keeps stats of client connection per-IP. */
typedef struct conn_client_stats_t {
/* Concurrent connection count from the specific address. 2^32 - 1 is most
* likely way too big for the amount of allowed file descriptors. */
uint32_t concurrent_count;
/* Connect count from the specific address. We use a token bucket here to
* track the rate and burst of connections from the same IP address.*/
token_bucket_ctr_t connect_count;
/* The client address attempted too many connections, per the connect_count
* rules, and thus is marked so defense(s) can be applied. It is
* synchronized using the approx_time(). */
time_t marked_until_ts;
} conn_client_stats_t;
/* This object is a top level object that contains everything related to the
* per-IP client DoS mitigation. Because it is per-IP, it is used in the geoip
* clientmap_entry_t object. */
typedef struct dos_client_stats_t {
/* Client connection statistics. */
conn_client_stats_t conn_stats;
/* Circuit creation statistics. This is only used if the circuit creation
* subsystem has been enabled (dos_cc_enabled). */
cc_client_stats_t cc_stats;
/** Number of times the circ_max_cell_queue_size limit has been reached. */
uint32_t num_circ_max_cell_queue_size;
} dos_client_stats_t;
/* General API. */
/* Stub. */
struct clientmap_entry_t;
void dos_init(void);
void dos_free_all(void);
void dos_consensus_has_changed(const networkstatus_t *ns);
int dos_enabled(void);
void dos_log_heartbeat(void);
void dos_geoip_entry_init(struct clientmap_entry_t *geoip_ent);
void dos_geoip_entry_about_to_free(const struct clientmap_entry_t *geoip_ent);
void dos_new_client_conn(or_connection_t *or_conn,
const char *transport_name);
void dos_close_client_conn(const or_connection_t *or_conn);
int dos_should_refuse_single_hop_client(void);
void dos_note_refuse_single_hop_client(void);
void dos_note_circ_max_outq(const channel_t *chan);
uint32_t dos_get_num_cc_marked_addr(void);
uint32_t dos_get_num_cc_marked_addr_maxq(void);
uint64_t dos_get_num_cc_rejected(void);
uint64_t dos_get_num_conn_addr_rejected(void);
uint64_t dos_get_num_conn_addr_connect_rejected(void);
uint64_t dos_get_num_single_hop_refused(void);
/*
* Circuit creation DoS mitigation subsystemn interface.
*/
/* DoSCircuitCreationEnabled default. Disabled by default. */
#define DOS_CC_ENABLED_DEFAULT 0
/* DoSCircuitCreationDefenseType maps to the dos_cc_defense_type_t enum. */
#define DOS_CC_DEFENSE_TYPE_DEFAULT DOS_CC_DEFENSE_REFUSE_CELL
/* DoSCircuitCreationMinConnections default */
#define DOS_CC_MIN_CONCURRENT_CONN_DEFAULT 3
/* DoSCircuitCreationRateTenths is 3 per seconds. */
#define DOS_CC_CIRCUIT_RATE_DEFAULT 3
/* DoSCircuitCreationBurst default. */
#define DOS_CC_CIRCUIT_BURST_DEFAULT 90
/* DoSCircuitCreationDefenseTimePeriod in seconds. */
#define DOS_CC_DEFENSE_TIME_PERIOD_DEFAULT (60 * 60)
/* Type of defense that we can use for the circuit creation DoS mitigation. */
typedef enum dos_cc_defense_type_t {
/* No defense used. */
DOS_CC_DEFENSE_NONE = 1,
/* Refuse any cells which means a DESTROY cell will be sent back. */
DOS_CC_DEFENSE_REFUSE_CELL = 2,
/* Maximum value that can be used. Useful for the boundaries of the
* consensus parameter. */
DOS_CC_DEFENSE_MAX = 2,
} dos_cc_defense_type_t;
void dos_cc_new_create_cell(channel_t *channel);
dos_cc_defense_type_t dos_cc_get_defense_type(channel_t *chan);
/*
* Concurrent connection DoS mitigation interface.
*/
/* DoSConnectionEnabled default. Disabled by default. */
#define DOS_CONN_ENABLED_DEFAULT 0
/* DoSConnectionMaxConcurrentCount default. */
#define DOS_CONN_MAX_CONCURRENT_COUNT_DEFAULT 100
/* DoSConnectionDefenseType maps to the dos_conn_defense_type_t enum. */
#define DOS_CONN_DEFENSE_TYPE_DEFAULT DOS_CONN_DEFENSE_CLOSE
/* DoSConnectionConnectRate default. Per second. */
#define DOS_CONN_CONNECT_RATE_DEFAULT 20
/* DoSConnectionConnectBurst default. Per second. */
#define DOS_CONN_CONNECT_BURST_DEFAULT 40
/* DoSConnectionConnectDefenseTimePeriod default. Set to 24 hours. */
#define DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_DEFAULT (24 * 60 * 60)
/* DoSCircuitCreationDefenseTimePeriod minimum value. Because we add a random
* offset to the marked timestamp, we need the minimum value to be non zero.
* We consider that 10 seconds is an acceptable lower bound. */
#define DOS_CONN_CONNECT_DEFENSE_TIME_PERIOD_MIN (10)
/* Type of defense that we can use for the concurrent connection DoS
* mitigation. */
typedef enum dos_conn_defense_type_t {
/* No defense used. */
DOS_CONN_DEFENSE_NONE = 1,
/* Close immediately the connection meaning refuse it. */
DOS_CONN_DEFENSE_CLOSE = 2,
/* Maximum value that can be used. Useful for the boundaries of the
* consensus parameter. */
DOS_CONN_DEFENSE_MAX = 2,
} dos_conn_defense_type_t;
dos_conn_defense_type_t dos_conn_addr_get_defense_type(const tor_addr_t *addr);
#ifdef DOS_PRIVATE
STATIC uint32_t get_param_conn_max_concurrent_count(
const networkstatus_t *ns);
STATIC uint32_t get_param_cc_circuit_burst(const networkstatus_t *ns);
STATIC uint32_t get_param_cc_min_concurrent_connection(
const networkstatus_t *ns);
STATIC uint32_t get_param_conn_connect_burst(const networkstatus_t *ns);
STATIC uint64_t get_circuit_rate_per_second(void);
STATIC void cc_stats_refill_bucket(cc_client_stats_t *stats,
const tor_addr_t *addr);
MOCK_DECL(STATIC unsigned int, get_param_cc_enabled,
(const networkstatus_t *ns));
MOCK_DECL(STATIC unsigned int, get_param_conn_enabled,
(const networkstatus_t *ns));
#endif /* defined(DOS_PRIVATE) */
#endif /* !defined(TOR_DOS_H) */
@@ -0,0 +1,16 @@
/* Copyright (c) 2021-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file dos_config.h
* @brief Header for core/or/dos_config.c
**/
#ifndef TOR_CORE_OR_DOS_CONFIG_H
#define TOR_CORE_OR_DOS_CONFIG_H
#include "lib/conf/conftypes.h"
extern const struct config_format_t dos_options_fmt;
#endif /* !defined(TOR_CORE_OR_DOS_CONFIG_H) */
@@ -0,0 +1,20 @@
/* Copyright (c) 2021-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file dos_options_st.h
* @brief Structure dos_options_t to hold options for the DoS subsystem.
**/
#ifndef TOR_CORE_OR_DOS_OPTIONS_ST_H
#define TOR_CORE_OR_DOS_OPTIONS_ST_H
#include "lib/conf/confdecl.h"
#define CONF_CONTEXT STRUCT
#include "core/or/dos_options.inc"
#undef CONF_CONTEXT
typedef struct dos_options_t dos_options_t;
#endif /* !defined(TOR_CORE_OR_DOS_OPTIONS_ST_H) */
@@ -0,0 +1,25 @@
/* Copyright (c) 2021-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file dos_sys.h
* @brief Header for core/or/dos_sys.c
**/
#ifndef TOR_CORE_OR_DOS_SYS_H
#define TOR_CORE_OR_DOS_SYS_H
struct dos_options_t;
const struct dos_options_t *dos_get_options(void);
extern const struct subsys_fns_t sys_dos;
/**
* Subsystem level for the metrics system.
*
* Defined here so that it can be shared between the real and stub
* definitions.
**/
#define DOS_SUBSYS_LEVEL (21)
#endif /* !defined(TOR_CORE_OR_DOS_SYS_H) */
@@ -0,0 +1,134 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file edge_connection_st.h
* @brief Edge-connection structure.
**/
#ifndef EDGE_CONNECTION_ST_H
#define EDGE_CONNECTION_ST_H
#include "core/or/or.h"
#include "core/or/connection_st.h"
#include "lib/evloop/token_bucket.h"
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
* connection, or an exit. */
struct edge_connection_t {
connection_t base_;
struct edge_connection_t *next_stream; /**< Points to the next stream at this
* edge, if any */
int package_window; /**< How many more relay cells can I send into the
* circuit? */
int deliver_window; /**< How many more relay cells can end at me? */
/** The circuit (if any) that this edge connection is using.
* Note that edges that use conflux should use the helpers
* in conflux_util.c instead of accessing this directly. */
struct circuit_t *on_circuit;
/** A pointer to which node in the circ this conn exits at. Set for AP
* connections and for hidden service exit connections.
* Note that edges that use conflux should use the helpers
* in conflux_util.c instead of accessing this directly. */
struct crypt_path_t *cpath_layer;
/* Hidden service connection identifier for edge connections. Used by the HS
* client-side code to identify client SOCKS connections and by the
* service-side code to match HS circuits with their streams. */
struct hs_ident_edge_conn_t *hs_ident;
uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit
* connection. Exit connections only. */
uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell
* for this connection */
streamid_t stream_id; /**< The stream ID used for this edge connection on its
* circuit */
/** The reason why this connection is closing; passed to the controller. */
uint16_t end_reason;
/** Bytes read since last call to control_event_stream_bandwidth_used() */
uint32_t n_read;
/** Bytes written since last call to control_event_stream_bandwidth_used() */
uint32_t n_written;
/** True iff this connection is for a DNS request only. */
unsigned int is_dns_request:1;
/** True iff this connection is for a PTR DNS request. (exit only) */
unsigned int is_reverse_dns_lookup:1;
unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge
* connections. Set once we've set the stream end,
* and check in connection_about_to_close_connection().
*/
/** Unique ID for directory requests; this used to be in connection_t, but
* that's going away and being used on channels instead. We still tag
* edge connections with dirreq_id from circuits, so it's copied here. */
uint64_t dirreq_id;
/* The following are flow control fields */
/** Used for rate limiting the read side of this edge connection when
* congestion control is enabled on its circuit. The XON cell ewma_drain_rate
* parameter is used to set the bucket limits. */
token_bucket_rw_t bucket;
/**
* Monotime timestamp of the last time we sent a flow control message
* for this edge, used to compute advisory rates */
uint64_t drain_start_usec;
/**
* Number of bytes written since we either emptied our buffers,
* or sent an advisory drate rate. Can wrap, buf if so,
* we must reset the usec timestamp above. (Or make this u64, idk).
*/
uint32_t drained_bytes;
uint32_t prev_drained_bytes;
/**
* N_EWMA of the drain rate of writes on this edge conn
* while buffers were present.
*/
uint32_t ewma_drain_rate;
/**
* The ewma drain rate the last time we sent an xon.
*/
uint32_t ewma_rate_last_sent;
/**
* The following fields are used to count the total bytes sent on this
* stream, and compare them to the number of XON and XOFFs received, so
* that clients can check rate limits of XOFF/XON to prevent dropmark
* attacks. */
uint32_t total_bytes_xmit;
/** Number of XOFFs received */
uint8_t num_xoff_recv;
/** Number of XONs received */
uint8_t num_xon_recv;
/**
* Flag that tells us if an XOFF has been sent; cleared when we send an XON.
* Used to avoid sending multiple */
uint8_t xoff_sent : 1;
/** Flag that tells us if an XOFF has been received; cleared when we get
* an XON. Used to ensure that this edge keeps reads on its edge socket
* disabled. */
uint8_t xoff_received : 1;
};
#endif /* !defined(EDGE_CONNECTION_ST_H) */
@@ -0,0 +1,108 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file entry_connection_st.h
* @brief Entry connection structure.
**/
#ifndef ENTRY_CONNECTION_ST_H
#define ENTRY_CONNECTION_ST_H
#include "core/or/edge_connection_st.h"
/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS
* connection, a DNS request, a TransPort connection or a NATD connection */
struct entry_connection_t {
struct edge_connection_t edge_;
/** Nickname of planned exit node -- used with .exit support. */
/* XXX prop220: we need to make chosen_exit_name able to encode Ed IDs too.
* That's logically part of the UI parts for prop220 though. */
char *chosen_exit_name;
socks_request_t *socks_request; /**< SOCKS structure describing request (AP
* only.) */
/* === Isolation related, AP only. === */
entry_port_cfg_t entry_cfg;
/** AP only: The newnym epoch in which we created this connection. */
unsigned nym_epoch;
/** AP only: The original requested address before we rewrote it. */
char *original_dest_address;
/* Other fields to isolate on already exist. The ClientAddr is addr. The
ClientProtocol is a combination of type and socks_request->
socks_version. SocksAuth is socks_request->username/password.
DestAddr is in socks_request->address. */
/** Number of times we've reassigned this application connection to
* a new circuit. We keep track because the timeout is longer if we've
* already retried several times. */
uint8_t num_socks_retries;
/** For AP connections only: buffer for data that we have sent
* optimistically, which we might need to re-send if we have to
* retry this connection. */
struct buf_t *pending_optimistic_data;
/* For AP connections only: buffer for data that we previously sent
* optimistically which we are currently re-sending as we retry this
* connection. */
struct buf_t *sending_optimistic_data;
/** If this is a DNSPort connection, this field holds the pending DNS
* request that we're going to try to answer. */
struct evdns_server_request *dns_server_request;
#define DEBUGGING_17659
#ifdef DEBUGGING_17659
uint16_t marked_pending_circ_line;
const char *marked_pending_circ_file;
#endif
#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10
/** Number of times we've launched a circuit to handle this stream. If
* it gets too high, that could indicate an inconsistency between our
* "launch a circuit to handle this stream" logic and our "attach our
* stream to one of the available circuits" logic. */
unsigned int num_circuits_launched:4;
/** True iff this stream must attach to a one-hop circuit (e.g. for
* begin_dir). */
unsigned int want_onehop:1;
/** True iff this stream should use a BEGIN_DIR relay command to establish
* itself rather than BEGIN (either via onehop or via a whole circuit). */
unsigned int use_begindir:1;
/** For AP connections only. If 1, and we fail to reach the chosen exit,
* stop requiring it. */
unsigned int chosen_exit_optional:1;
/** For AP connections only. If non-zero, this exit node was picked as
* a result of the TrackHostExit, and the value decrements every time
* we fail to complete a circuit to our chosen exit -- if it reaches
* zero, abandon the associated mapaddress. */
unsigned int chosen_exit_retries:3;
/** True iff this is an AP connection that came from a transparent or
* NATd connection */
unsigned int is_transparent_ap:1;
/** For AP connections only: Set if this connection's target exit node
* allows optimistic data (that is, data sent on this stream before
* the exit has sent a CONNECTED cell) and we have chosen to use it.
*/
unsigned int may_use_optimistic_data : 1;
/** True iff this is a connection to a HS that has PoW defenses enabled,
* so we know not to apply the usual SOCKS timeout. */
unsigned int hs_with_pow_conn : 1;
};
/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/
#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_))
#endif /* !defined(ENTRY_CONNECTION_ST_H) */
@@ -0,0 +1,61 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file entry_port_cfg_st.h
* @brief Configuration structure for client ports.
**/
#ifndef ENTRY_PORT_CFG_ST_H
#define ENTRY_PORT_CFG_ST_H
#include "lib/cc/torint.h"
#include "core/or/or.h"
struct entry_port_cfg_t {
/* Client port types (socks, dns, trans, natd) only: */
uint8_t isolation_flags; /**< Zero or more isolation flags */
int session_group; /**< A session group, or -1 if this port is not in a
* session group. */
/* Socks only: */
/** When both no-auth and user/pass are advertised by a SOCKS client, select
* no-auth. */
unsigned int socks_prefer_no_auth : 1;
/** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */
unsigned int socks_iso_keep_alive : 1;
/* Client port types only: */
unsigned int ipv4_traffic : 1;
unsigned int ipv6_traffic : 1;
unsigned int prefer_ipv6 : 1;
unsigned int dns_request : 1;
unsigned int onion_traffic : 1;
/** For a socks listener: should we cache IPv4/IPv6 DNS information that
* exit nodes tell us?
*
* @{ */
unsigned int cache_ipv4_answers : 1;
unsigned int cache_ipv6_answers : 1;
/** @} */
/** For a socks listeners: if we find an answer in our client-side DNS cache,
* should we use it?
*
* @{ */
unsigned int use_cached_ipv4_answers : 1;
unsigned int use_cached_ipv6_answers : 1;
/** @} */
/** For socks listeners: When we can automap an address to IPv4 or IPv6,
* do we prefer IPv6? */
unsigned int prefer_ipv6_virtaddr : 1;
/** For socks listeners: can we send back the extended SOCKS5 error code? */
unsigned int extended_socks5_codes : 1;
};
#endif /* !defined(ENTRY_PORT_CFG_ST_H) */
@@ -0,0 +1,47 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file extend_info_st.h
* @brief Extend-info structure.
**/
#ifndef EXTEND_INFO_ST_H
#define EXTEND_INFO_ST_H
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
/** Largest number of addresses we handle in an extend_info.
*
* More are permitted in an EXTEND cell, but we won't handle them. */
#define EXTEND_INFO_MAX_ADDRS 2
/** Information on router used when extending a circuit. We don't need a
* full routerinfo_t to extend: we only need addr:port:keyid to build an OR
* connection, and onion_key to create the onionskin. Note that for one-hop
* general-purpose tunnels, the onion_key is NULL. */
struct extend_info_t {
char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for
* display. */
/** Hash of this router's RSA identity key. */
char identity_digest[DIGEST_LEN];
/** Ed25519 identity for this router, if any. */
ed25519_public_key_t ed_identity;
/** IP/Port values for this hop's ORPort(s). Any unused values are set
* to a null address. */
tor_addr_port_t orports[EXTEND_INFO_MAX_ADDRS];
/** TAP onion key for this hop. */
crypto_pk_t *onion_key;
/** Ntor onion key for this hop. */
curve25519_public_key_t curve25519_onion_key;
/** True if this hop is to be used as an _exit_,
* and it also supports supports NtorV3 _and_ negotiation
* of congestion control parameters */
bool exit_supports_congestion_control;
};
#endif /* !defined(EXTEND_INFO_ST_H) */
@@ -0,0 +1,44 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file extendinfo.h
* @brief Header for core/or/extendinfo.c
**/
#ifndef TOR_CORE_OR_EXTENDINFO_H
#define TOR_CORE_OR_EXTENDINFO_H
extend_info_t *extend_info_new(const char *nickname,
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
crypto_pk_t *onion_key,
const struct curve25519_public_key_t *ntor_key,
const tor_addr_t *addr, uint16_t port,
const struct protover_summary_flags_t *pv,
bool for_exit_use);
extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect,
bool for_exit);
extend_info_t *extend_info_dup(extend_info_t *info);
void extend_info_free_(extend_info_t *info);
#define extend_info_free(info) \
FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
int extend_info_addr_is_allowed(const tor_addr_t *addr);
int extend_info_supports_tap(const extend_info_t* ei);
int extend_info_supports_ntor(const extend_info_t* ei);
int extend_info_supports_ntor_v3(const extend_info_t *ei);
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
bool extend_info_has_orport(const extend_info_t *ei,
const tor_addr_t *addr, uint16_t port);
int extend_info_add_orport(extend_info_t *ei,
const tor_addr_t *addr,
uint16_t port);
const tor_addr_port_t *extend_info_get_orport(const extend_info_t *ei,
int family);
const tor_addr_port_t *extend_info_pick_orport(const extend_info_t *ei);
bool extend_info_any_orport_addr_is_internal(const extend_info_t *ei);
#endif /* !defined(TOR_CORE_OR_EXTENDINFO_H) */
@@ -0,0 +1,50 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file half_edge_st.h
* @brief Half-open connection structure.
**/
#ifndef HALF_EDGE_ST_H
#define HALF_EDGE_ST_H
#include "core/or/or.h"
/**
* Struct to track a connection that we closed that the other end
* still thinks is open. Exists in origin_circuit_t.half_streams until
* we get an end cell or a resolved cell for this stream id.
*/
typedef struct half_edge_t {
/** stream_id for the half-closed connection */
streamid_t stream_id;
/** How many sendme's can the other end still send, based on how
* much data we had sent at the time of close */
int sendmes_pending;
/** How much more data can the other end still send, based on
* our deliver window */
int data_pending;
/**
* Monotime timestamp of when the other end should have successfully
* shut down the stream and stop sending data, based on the larger
* of circuit RTT and CBT. Used if 'used_ccontrol' is true, to expire
* the half_edge at this monotime timestamp. */
uint64_t end_ack_expected_usec;
/**
* Did this edge use congestion control? If so, use
* timer instead of pending data approach */
unsigned int used_ccontrol : 1;
/** Is there a connected cell pending? */
unsigned int connected_pending : 1;
} half_edge_t;
#endif /* !defined(HALF_EDGE_ST_H) */
@@ -0,0 +1,29 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file listener_connection_st.h
* @brief Listener connection structure.
**/
#ifndef LISTENER_CONNECTION_ST_H
#define LISTENER_CONNECTION_ST_H
#include "core/or/connection_st.h"
/** Subtype of connection_t; used for a listener socket. */
struct listener_connection_t {
connection_t base_;
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
* to the evdns_server_port it uses to listen to and answer connections. */
struct evdns_server_port *dns_server_port;
entry_port_cfg_t entry_cfg;
};
#endif /* !defined(LISTENER_CONNECTION_ST_H) */
@@ -0,0 +1,72 @@
/* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file ocirc_event.h
* \brief Header file for ocirc_event.c
**/
#ifndef TOR_OCIRC_EVENT_H
#define TOR_OCIRC_EVENT_H
#include <stdbool.h>
#include "lib/cc/torint.h"
#include "lib/pubsub/pubsub.h"
/** Used to indicate the type of a circuit event passed to the controller.
* The various types are defined in control-spec.txt */
typedef enum circuit_status_event_t {
CIRC_EVENT_LAUNCHED = 0,
CIRC_EVENT_BUILT = 1,
CIRC_EVENT_EXTENDED = 2,
CIRC_EVENT_FAILED = 3,
CIRC_EVENT_CLOSED = 4,
} circuit_status_event_t;
/** Message for origin circuit state update */
typedef struct ocirc_state_msg_t {
uint32_t gid; /**< global ID (only origin circuits have them) */
int state; /**< new circuit state */
bool onehop; /**< one-hop circuit? */
} ocirc_state_msg_t;
DECLARE_MESSAGE(ocirc_state, ocirc_state, ocirc_state_msg_t *);
/**
* Message when a channel gets associated to a circuit.
*
* This doesn't always correspond to something in circuitbuild.c
* setting the n_chan field in the circuit. For some reason, if
* circuit_handle_first_hop() launches a new circuit, it doesn't set
* the n_chan field.
*/
typedef struct ocirc_chan_msg_t {
uint32_t gid; /**< global ID */
uint64_t chan; /**< channel ID */
bool onehop; /**< one-hop circuit? */
} ocirc_chan_msg_t;
DECLARE_MESSAGE(ocirc_chan, ocirc_chan, ocirc_chan_msg_t *);
/**
* Message for origin circuit status event
*
* This contains information that ends up in CIRC control protocol events.
*/
typedef struct ocirc_cevent_msg_t {
uint32_t gid; /**< global ID */
int evtype; /**< event type */
int reason; /**< reason */
bool onehop; /**< one-hop circuit? */
} ocirc_cevent_msg_t;
DECLARE_MESSAGE(ocirc_cevent, ocirc_cevent, ocirc_cevent_msg_t *);
#ifdef OCIRC_EVENT_PRIVATE
void ocirc_state_publish(ocirc_state_msg_t *msg);
void ocirc_chan_publish(ocirc_chan_msg_t *msg);
void ocirc_cevent_publish(ocirc_cevent_msg_t *msg);
#endif
#endif /* !defined(TOR_OCIRC_EVENT_H) */
@@ -0,0 +1,91 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file onion.h
* \brief Header file for onion.c.
**/
#ifndef TOR_ONION_H
#define TOR_ONION_H
struct create_cell_t;
struct curve25519_keypair_t;
struct curve25519_public_key_t;
#include "lib/crypt_ops/crypto_ed25519.h"
#define MAX_ONIONSKIN_CHALLENGE_LEN 255
#define MAX_ONIONSKIN_REPLY_LEN 255
/** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */
typedef struct create_cell_t {
/** The cell command. One of CREATE{,_FAST,2} */
uint8_t cell_type;
/** One of the ONION_HANDSHAKE_TYPE_* values */
uint16_t handshake_type;
/** The number of bytes used in <b>onionskin</b>. */
uint16_t handshake_len;
/** The client-side message for the circuit creation handshake. */
uint8_t onionskin[CELL_PAYLOAD_SIZE - 4];
} create_cell_t;
/** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */
typedef struct created_cell_t {
/** The cell command. One of CREATED{,_FAST,2} */
uint8_t cell_type;
/** The number of bytes used in <b>reply</b>. */
uint16_t handshake_len;
/** The server-side message for the circuit creation handshake. */
uint8_t reply[CELL_PAYLOAD_SIZE - 2];
} created_cell_t;
/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */
typedef struct extend_cell_t {
/** One of RELAY_EXTEND or RELAY_EXTEND2 */
uint8_t cell_type;
/** An IPv4 address and port for the node we're connecting to. */
tor_addr_port_t orport_ipv4;
/** An IPv6 address and port for the node we're connecting to. */
tor_addr_port_t orport_ipv6;
/** Identity fingerprint of the node we're connecting to.*/
uint8_t node_id[DIGEST_LEN];
/** Ed25519 public identity key. Zero if not set. */
struct ed25519_public_key_t ed_pubkey;
/** The "create cell" embedded in this extend cell. Note that unlike the
* create cells we generate ourselves, this create cell can have a handshake
* type we don't recognize. */
create_cell_t create_cell;
} extend_cell_t;
/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */
typedef struct extended_cell_t {
/** One of RELAY_EXTENDED or RELAY_EXTENDED2. */
uint8_t cell_type;
/** The "created cell" embedded in this extended cell. */
created_cell_t created_cell;
} extended_cell_t;
void create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
uint16_t handshake_type, uint16_t handshake_len,
const uint8_t *onionskin);
int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in);
int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in);
MOCK_DECL(int,extend_cell_parse,(extend_cell_t *cell_out,
const uint8_t command,
const uint8_t *payload_in,
size_t payload_len));
int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command,
const uint8_t *payload_in, size_t payload_len);
int create_cell_format(cell_t *cell_out, const create_cell_t *cell_in);
int create_cell_format_relayed(cell_t *cell_out, const create_cell_t *cell_in);
int created_cell_format(cell_t *cell_out, const created_cell_t *cell_in);
int extend_cell_format(uint8_t *command_out, uint16_t *len_out,
uint8_t *payload_out, const extend_cell_t *cell_in);
int extended_cell_format(uint8_t *command_out, uint16_t *len_out,
uint8_t *payload_out, const extended_cell_t *cell_in);
#endif /* !defined(TOR_ONION_H) */
@@ -0,0 +1,993 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file or.h
* \brief Master header file for Tor-specific functionality.
**/
#ifndef TOR_OR_H
#define TOR_OR_H
#include "orconfig.h"
#include "lib/cc/torint.h"
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include "lib/arch/bytes.h"
#include "lib/cc/compat_compiler.h"
#include "lib/container/map.h"
#include "lib/buf/buffers.h"
#include "lib/container/smartlist.h"
#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_rsa.h"
#include "lib/ctime/di_ops.h"
#include "lib/defs/dh_sizes.h"
#include "lib/encoding/binascii.h"
#include "lib/encoding/cstring.h"
#include "lib/encoding/time_fmt.h"
#include "lib/err/torerr.h"
#include "lib/fs/dir.h"
#include "lib/fs/files.h"
#include "lib/fs/mmap.h"
#include "lib/fs/path.h"
#include "lib/fs/userdb.h"
#include "lib/geoip/country.h"
#include "lib/intmath/addsub.h"
#include "lib/intmath/bits.h"
#include "lib/intmath/cmp.h"
#include "lib/intmath/logic.h"
#include "lib/intmath/muldiv.h"
#include "lib/log/escape.h"
#include "lib/log/ratelim.h"
#include "lib/log/util_bug.h"
#include "lib/malloc/malloc.h"
#include "lib/net/address.h"
#include "lib/net/inaddr.h"
#include "lib/net/socket.h"
#include "lib/string/compat_ctype.h"
#include "lib/string/compat_string.h"
#include "lib/string/parse_int.h"
#include "lib/string/printf.h"
#include "lib/string/scanf.h"
#include "lib/string/util_string.h"
#include "lib/testsupport/testsupport.h"
#include "lib/thread/threads.h"
#include "lib/time/compat_time.h"
#include "lib/wallclock/approx_time.h"
#include "lib/wallclock/timeval.h"
#include "ht.h"
// These, more than other includes, are for keeping the other struct
// definitions working. We should remove them when we minimize our includes.
#include "core/or/entry_port_cfg_st.h"
struct ed25519_public_key_t;
struct curve25519_public_key_t;
/* These signals are defined to help handle_control_signal work.
*/
#ifndef SIGHUP
#define SIGHUP 1
#endif
#ifndef SIGINT
#define SIGINT 2
#endif
#ifndef SIGUSR1
#define SIGUSR1 10
#endif
#ifndef SIGUSR2
#define SIGUSR2 12
#endif
#ifndef SIGTERM
#define SIGTERM 15
#endif
/* Controller signals start at a high number so we don't
* conflict with system-defined signals. */
#define SIGNEWNYM 129
#define SIGCLEARDNSCACHE 130
#define SIGHEARTBEAT 131
#define SIGACTIVE 132
#define SIGDORMANT 133
#if (SIZEOF_CELL_T != 0)
/* On Irix, stdlib.h defines a cell_t type, so we need to make sure
* that our stuff always calls cell_t something different. */
#define cell_t tor_cell_t
#endif
/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */
#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_))
/** Length of longest allowable configured nickname. */
#define MAX_NICKNAME_LEN 19
/** Length of a router identity encoded as a hexadecimal digest, plus
* possible dollar sign. */
#define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1)
/** Maximum length of verbose router identifier: dollar sign, hex ID digest,
* equal sign or tilde, nickname. */
#define MAX_VERBOSE_NICKNAME_LEN (1+HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN)
/** For HTTP parsing: Maximum number of bytes we'll accept in the headers
* of an HTTP request or response. */
#define MAX_HEADERS_SIZE 50000
/** Maximum size, in bytes, of a single router descriptor uploaded to us
* as a directory authority. Caches and clients fetch whatever descriptors
* the authorities tell them to fetch, and don't care about size. */
#define MAX_DESCRIPTOR_UPLOAD_SIZE 20000
/** Maximum size of a single extrainfo document, as above. */
#define MAX_EXTRAINFO_UPLOAD_SIZE 50000
/** Minimum lifetime for an onion key in days. */
#define MIN_ONION_KEY_LIFETIME_DAYS (1)
/** Maximum lifetime for an onion key in days. */
#define MAX_ONION_KEY_LIFETIME_DAYS (90)
/** Default lifetime for an onion key in days. */
#define DEFAULT_ONION_KEY_LIFETIME_DAYS (28)
/** Minimum grace period for acceptance of an onion key in days.
* The maximum value is defined in proposal #274 as being the current network
* consensus parameter for "onion-key-rotation-days". */
#define MIN_ONION_KEY_GRACE_PERIOD_DAYS (1)
/** Default grace period for acceptance of an onion key in days. */
#define DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS (7)
/** How often we should check the network consensus if it is time to rotate or
* expire onion keys. */
#define ONION_KEY_CONSENSUS_CHECK_INTERVAL (60*60)
/** How often do we rotate TLS contexts? */
#define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60)
/** How old do we allow a router to get before removing it
* from the router list? In seconds. */
#define ROUTER_MAX_AGE (60*60*48)
/** How old can a router get before we (as a server) will no longer
* consider it live? In seconds. */
#define ROUTER_MAX_AGE_TO_PUBLISH (60*60*24)
/** How old do we let a saved descriptor get before force-removing it? */
#define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5)
/* Proxy client types */
#define PROXY_NONE 0
#define PROXY_CONNECT 1
#define PROXY_SOCKS4 2
#define PROXY_SOCKS5 3
#define PROXY_HAPROXY 4
/* !!!! If there is ever a PROXY_* type over 7, we must grow the proxy_type
* field in or_connection_t */
/* Pluggable transport proxy type. Don't use this in or_connection_t,
* instead use the actual underlying proxy type (see above). */
#define PROXY_PLUGGABLE 5
/** How many circuits do we want simultaneously in-progress to handle
* a given stream? */
#define MIN_CIRCUITS_HANDLING_STREAM 2
/* These RELAY_COMMAND constants define values for relay cell commands, and
* must match those defined in tor-spec.txt. */
#define RELAY_COMMAND_BEGIN 1
#define RELAY_COMMAND_DATA 2
#define RELAY_COMMAND_END 3
#define RELAY_COMMAND_CONNECTED 4
#define RELAY_COMMAND_SENDME 5
#define RELAY_COMMAND_EXTEND 6
#define RELAY_COMMAND_EXTENDED 7
#define RELAY_COMMAND_TRUNCATE 8
#define RELAY_COMMAND_TRUNCATED 9
#define RELAY_COMMAND_DROP 10
#define RELAY_COMMAND_RESOLVE 11
#define RELAY_COMMAND_RESOLVED 12
#define RELAY_COMMAND_BEGIN_DIR 13
#define RELAY_COMMAND_EXTEND2 14
#define RELAY_COMMAND_EXTENDED2 15
/* Conflux */
#define RELAY_COMMAND_CONFLUX_LINK 19
#define RELAY_COMMAND_CONFLUX_LINKED 20
#define RELAY_COMMAND_CONFLUX_LINKED_ACK 21
#define RELAY_COMMAND_CONFLUX_SWITCH 22
#define RELAY_COMMAND_ESTABLISH_INTRO 32
#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33
#define RELAY_COMMAND_INTRODUCE1 34
#define RELAY_COMMAND_INTRODUCE2 35
#define RELAY_COMMAND_RENDEZVOUS1 36
#define RELAY_COMMAND_RENDEZVOUS2 37
#define RELAY_COMMAND_INTRO_ESTABLISHED 38
#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39
#define RELAY_COMMAND_INTRODUCE_ACK 40
#define RELAY_COMMAND_PADDING_NEGOTIATE 41
#define RELAY_COMMAND_PADDING_NEGOTIATED 42
#define RELAY_COMMAND_XOFF 43
#define RELAY_COMMAND_XON 44
/* Reasons why an OR connection is closed. */
#define END_OR_CONN_REASON_DONE 1
#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */
#define END_OR_CONN_REASON_OR_IDENTITY 3
#define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */
#define END_OR_CONN_REASON_TIMEOUT 5
#define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */
#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */
#define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */
#define END_OR_CONN_REASON_PT_MISSING 9 /* PT failed or not available */
#define END_OR_CONN_REASON_TLS_ERROR 10 /* Problem in TLS protocol */
#define END_OR_CONN_REASON_MISC 11
/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for
* documentation of these. The values must match. */
#define END_STREAM_REASON_MISC 1
#define END_STREAM_REASON_RESOLVEFAILED 2
#define END_STREAM_REASON_CONNECTREFUSED 3
#define END_STREAM_REASON_EXITPOLICY 4
#define END_STREAM_REASON_DESTROY 5
#define END_STREAM_REASON_DONE 6
#define END_STREAM_REASON_TIMEOUT 7
#define END_STREAM_REASON_NOROUTE 8
#define END_STREAM_REASON_HIBERNATING 9
#define END_STREAM_REASON_INTERNAL 10
#define END_STREAM_REASON_RESOURCELIMIT 11
#define END_STREAM_REASON_CONNRESET 12
#define END_STREAM_REASON_TORPROTOCOL 13
#define END_STREAM_REASON_NOTDIRECTORY 14
#define END_STREAM_REASON_ENTRYPOLICY 15
/* These high-numbered end reasons are not part of the official spec,
* and are not intended to be put in relay end cells. They are here
* to be more informative when sending back socks replies to the
* application. */
/* XXXX 256 is no longer used; feel free to reuse it. */
/** We were unable to attach the connection to any circuit at all. */
/* XXXX the ways we use this one don't make a lot of sense. */
#define END_STREAM_REASON_CANT_ATTACH 257
/** We can't connect to any directories at all, so we killed our streams
* before they can time out. */
#define END_STREAM_REASON_NET_UNREACHABLE 258
/** This is a SOCKS connection, and the client used (or misused) the SOCKS
* protocol in a way we couldn't handle. */
#define END_STREAM_REASON_SOCKSPROTOCOL 259
/** This is a transparent proxy connection, but we can't extract the original
* target address:port. */
#define END_STREAM_REASON_CANT_FETCH_ORIG_DEST 260
/** This is a connection on the NATD port, and the destination IP:Port was
* either ill-formed or out-of-range. */
#define END_STREAM_REASON_INVALID_NATD_DEST 261
/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1);
* you don't want to do that over a randomly chosen exit */
#define END_STREAM_REASON_PRIVATE_ADDR 262
/** This is an HTTP tunnel connection and the client used or misused HTTP in a
* way we can't handle.
*/
#define END_STREAM_REASON_HTTPPROTOCOL 263
/** Bitwise-and this value with endreason to mask out all flags. */
#define END_STREAM_REASON_MASK 511
/** Bitwise-or this with the argument to control_event_stream_status
* to indicate that the reason came from an END cell. */
#define END_STREAM_REASON_FLAG_REMOTE 512
/** Bitwise-or this with the argument to control_event_stream_status
* to indicate that we already sent a CLOSED stream event. */
#define END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED 1024
/** Bitwise-or this with endreason to indicate that we already sent
* a socks reply, and no further reply needs to be sent from
* connection_mark_unattached_ap(). */
#define END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED 2048
/* 'type' values to use in RESOLVED cells. Specified in tor-spec.txt. */
#define RESOLVED_TYPE_HOSTNAME 0
#define RESOLVED_TYPE_IPV4 4
#define RESOLVED_TYPE_IPV6 6
#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0
#define RESOLVED_TYPE_ERROR 0xF1
/* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE
* call; they only go to the controller for tracking */
/* Closing introduction point that were opened in parallel. */
#define END_CIRC_REASON_IP_NOW_REDUNDANT -4
/** Our post-timeout circuit time measurement period expired.
* We must give up now */
#define END_CIRC_REASON_MEASUREMENT_EXPIRED -3
/** We couldn't build a path for this circuit. */
#define END_CIRC_REASON_NOPATH -2
/** Catch-all "other" reason for closing origin circuits. */
#define END_CIRC_AT_ORIGIN -1
/* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt
* section 5.4 for documentation of these. */
#define END_CIRC_REASON_MIN_ 0
#define END_CIRC_REASON_NONE 0
#define END_CIRC_REASON_TORPROTOCOL 1
#define END_CIRC_REASON_INTERNAL 2
#define END_CIRC_REASON_REQUESTED 3
#define END_CIRC_REASON_HIBERNATING 4
#define END_CIRC_REASON_RESOURCELIMIT 5
#define END_CIRC_REASON_CONNECTFAILED 6
#define END_CIRC_REASON_OR_IDENTITY 7
#define END_CIRC_REASON_CHANNEL_CLOSED 8
#define END_CIRC_REASON_FINISHED 9
#define END_CIRC_REASON_TIMEOUT 10
#define END_CIRC_REASON_DESTROYED 11
#define END_CIRC_REASON_NOSUCHSERVICE 12
#define END_CIRC_REASON_MAX_ 12
/** Bitwise-OR this with the argument to circuit_mark_for_close() or
* control_event_circuit_status() to indicate that the reason was
* passed through from a destroy or truncate cell. */
#define END_CIRC_REASON_FLAG_REMOTE 512
/** Length of v2 descriptor ID (32 base32 chars = 160 bits).
*
* XXX: It is still used by v3 code but should be renamed or maybe removed. */
#define REND_DESC_ID_V2_LEN_BASE32 BASE32_DIGEST_LEN
/** Maximum length of authorized client names for a hidden service. */
#define REND_CLIENTNAME_MAX_LEN 16
/** Length of the rendezvous cookie that is used to connect circuits at the
* rendezvous point. */
#define REND_COOKIE_LEN DIGEST_LEN
/** Client authorization type that a hidden service performs. */
typedef enum rend_auth_type_t {
REND_NO_AUTH = 0,
REND_V3_AUTH = 1, /* Dummy flag to allow adding v3 services on the
* control port */
} rend_auth_type_t;
/* Stub because we can't include hs_ident.h. */
struct hs_ident_edge_conn_t;
struct hs_ident_dir_conn_t;
struct hs_ident_circuit_t;
typedef struct hsdir_index_t hsdir_index_t;
/** Time interval for tracking replays of DH public keys received in
* INTRODUCE2 cells. Used only to avoid launching multiple
* simultaneous attempts to connect to the same rendezvous point. */
#define REND_REPLAY_TIME_INTERVAL (5 * 60)
/** Used to indicate which way a cell is going on a circuit. */
typedef enum {
CELL_DIRECTION_IN=1, /**< The cell is moving towards the origin. */
CELL_DIRECTION_OUT=2, /**< The cell is moving away from the origin. */
} cell_direction_t;
/**
* An enum to allow us to specify which channel in a circuit
* we're interested in.
*
* This is needed because our data structures and other fields
* for channel delivery are disassociated from the channel.
*/
typedef enum {
CIRCUIT_N_CHAN = 0,
CIRCUIT_P_CHAN = 1
} circuit_channel_direction_t;
/** Initial value for both sides of a circuit transmission window when the
* circuit is initialized. Measured in cells. */
#define CIRCWINDOW_START 1000
#define CIRCWINDOW_START_MIN 100
#define CIRCWINDOW_START_MAX 1000
/** Amount to increment a circuit window when we get a circuit SENDME. */
#define CIRCWINDOW_INCREMENT 100
/** Initial value on both sides of a stream transmission window when the
* stream is initialized. Measured in cells. */
#define STREAMWINDOW_START 500
#define STREAMWINDOW_START_MAX 500
/** Amount to increment a stream window when we get a stream SENDME. */
#define STREAMWINDOW_INCREMENT 50
/** Maximum number of queued cells on a circuit for which we are the
* midpoint before we give up and kill it. This must be >= circwindow
* to avoid killing innocent circuits, and >= circwindow*2 to give
* leaky-pipe a chance of working someday. The ORCIRC_MAX_MIDDLE_KILL_THRESH
* ratio controls the margin of error between emitting a warning and
* killing the circuit.
*/
#define ORCIRC_MAX_MIDDLE_CELLS (CIRCWINDOW_START_MAX*2)
/** Ratio of hard (circuit kill) to soft (warning) thresholds for the
* ORCIRC_MAX_MIDDLE_CELLS tests.
*/
#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f)
/* Cell commands. These values are defined in tor-spec.txt. */
#define CELL_PADDING 0
#define CELL_CREATE 1
#define CELL_CREATED 2
#define CELL_RELAY 3
#define CELL_DESTROY 4
#define CELL_CREATE_FAST 5
#define CELL_CREATED_FAST 6
#define CELL_VERSIONS 7
#define CELL_NETINFO 8
#define CELL_RELAY_EARLY 9
#define CELL_CREATE2 10
#define CELL_CREATED2 11
#define CELL_PADDING_NEGOTIATE 12
#define CELL_VPADDING 128
#define CELL_CERTS 129
#define CELL_AUTH_CHALLENGE 130
#define CELL_AUTHENTICATE 131
#define CELL_AUTHORIZE 132
#define CELL_COMMAND_MAX_ 132
/** How long to test reachability before complaining to the user. */
#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)
/** Legal characters in a nickname. */
#define LEGAL_NICKNAME_CHARACTERS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
/** Name chosen by routers that don't configure nicknames */
#define UNNAMED_ROUTER_NICKNAME "Unnamed"
/** Number of bytes in a SOCKS4 header. */
#define SOCKS4_NETWORK_LEN 8
/*
* Relay payload:
* Relay command [1 byte]
* Recognized [2 bytes]
* Stream ID [2 bytes]
* Partial SHA-1 [4 bytes]
* Length [2 bytes]
* Relay payload [498 bytes]
*/
/** Number of bytes in a cell, minus cell header. */
#define CELL_PAYLOAD_SIZE 509
/** Number of bytes in a cell transmitted over the network, in the longest
* form */
#define CELL_MAX_NETWORK_SIZE 514
/** Maximum length of a header on a variable-length cell. */
#define VAR_CELL_MAX_HEADER_SIZE 7
static int get_cell_network_size(int wide_circ_ids);
static inline int get_cell_network_size(int wide_circ_ids)
{
return wide_circ_ids ? CELL_MAX_NETWORK_SIZE : CELL_MAX_NETWORK_SIZE - 2;
}
static int get_var_cell_header_size(int wide_circ_ids);
static inline int get_var_cell_header_size(int wide_circ_ids)
{
return wide_circ_ids ? VAR_CELL_MAX_HEADER_SIZE :
VAR_CELL_MAX_HEADER_SIZE - 2;
}
static int get_circ_id_size(int wide_circ_ids);
static inline int get_circ_id_size(int wide_circ_ids)
{
return wide_circ_ids ? 4 : 2;
}
/** Number of bytes in a relay cell's header (not including general cell
* header). */
#define RELAY_HEADER_SIZE (1+2+2+4+2)
/** Largest number of bytes that can fit in a relay cell payload. */
#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE)
/** Identifies a circuit on an or_connection */
typedef uint32_t circid_t;
/** Identifies a stream on a circuit */
typedef uint16_t streamid_t;
/* channel_t typedef; struct channel_t is in channel.h */
typedef struct channel_t channel_t;
/* channel_listener_t typedef; struct channel_listener_t is in channel.h */
typedef struct channel_listener_t channel_listener_t;
/* TLS channel stuff */
typedef struct channel_tls_t channel_tls_t;
/* circuitmux_t typedef; struct circuitmux_t is in circuitmux.h */
typedef struct circuitmux_t circuitmux_t;
typedef struct cell_t cell_t;
typedef struct var_cell_t var_cell_t;
typedef struct packed_cell_t packed_cell_t;
typedef struct cell_queue_t cell_queue_t;
typedef struct destroy_cell_t destroy_cell_t;
typedef struct destroy_cell_queue_t destroy_cell_queue_t;
typedef struct ext_or_cmd_t ext_or_cmd_t;
/** Beginning of a RELAY cell payload. */
typedef struct {
uint8_t command; /**< The end-to-end relay command. */
uint16_t recognized; /**< Used to tell whether cell is for us. */
streamid_t stream_id; /**< Which stream is this cell associated with? */
char integrity[4]; /**< Used to tell whether cell is corrupted. */
uint16_t length; /**< How long is the payload body? */
} relay_header_t;
typedef struct socks_request_t socks_request_t;
typedef struct entry_port_cfg_t entry_port_cfg_t;
typedef struct server_port_cfg_t server_port_cfg_t;
/** Minimum length of the random part of an AUTH_CHALLENGE cell. */
#define OR_AUTH_CHALLENGE_LEN 32
/**
* @name Certificate types for CERTS cells.
*
* These values are defined by the protocol, and affect how an X509
* certificate in a CERTS cell is interpreted and used.
*
* @{ */
/** A certificate that authenticates a TLS link key. The subject key
* must match the key used in the TLS handshake; it must be signed by
* the identity key. */
#define OR_CERT_TYPE_TLS_LINK 1
/** A self-signed identity certificate. The subject key must be a
* 1024-bit RSA key. */
#define OR_CERT_TYPE_ID_1024 2
/** A certificate that authenticates a key used in an AUTHENTICATE cell
* in the v3 handshake. The subject key must be a 1024-bit RSA key; it
* must be signed by the identity key */
#define OR_CERT_TYPE_AUTH_1024 3
/* DOCDOC */
#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7
/**@}*/
/** The first supported type of AUTHENTICATE cell. It contains
* a bunch of structures signed with an RSA1024 key. The signed
* structures include a HMAC using negotiated TLS secrets, and a digest
* of all cells sent or received before the AUTHENTICATE cell (including
* the random server-generated AUTH_CHALLENGE cell).
*/
#define AUTHTYPE_RSA_SHA256_TLSSECRET 1
/** As AUTHTYPE_RSA_SHA256_TLSSECRET, but instead of using the
* negotiated TLS secrets, uses exported keying material from the TLS
* session as described in RFC 5705.
*
* Not used by today's tors, since everything that supports this
* also supports ED25519_SHA256_5705, which is better.
**/
#define AUTHTYPE_RSA_SHA256_RFC5705 2
/** As AUTHTYPE_RSA_SHA256_RFC5705, but uses an Ed25519 identity key to
* authenticate. */
#define AUTHTYPE_ED25519_SHA256_RFC5705 3
/*
* NOTE: authchallenge_type_is_better() relies on these AUTHTYPE codes
* being sorted in order of preference. If we someday add one with
* a higher numerical value that we don't like as much, we should revise
* authchallenge_type_is_better().
*/
/** The length of the part of the AUTHENTICATE cell body that the client and
* server can generate independently (when using RSA_SHA256_TLSSECRET). It
* contains everything except the client's timestamp, the client's randomly
* generated nonce, and the signature. */
#define V3_AUTH_FIXED_PART_LEN (8+(32*6))
/** The length of the part of the AUTHENTICATE cell body that the client
* signs. */
#define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16)
typedef struct or_handshake_certs_t or_handshake_certs_t;
typedef struct or_handshake_state_t or_handshake_state_t;
/** Length of Extended ORPort connection identifier. */
#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */
typedef struct connection_t connection_t;
typedef struct control_connection_t control_connection_t;
typedef struct dir_connection_t dir_connection_t;
typedef struct edge_connection_t edge_connection_t;
typedef struct entry_connection_t entry_connection_t;
typedef struct listener_connection_t listener_connection_t;
typedef struct or_connection_t or_connection_t;
/** Cast a connection_t subtype pointer to a connection_t **/
#define TO_CONN(c) (&(((c)->base_)))
/** Cast a entry_connection_t subtype pointer to a connection_t **/
#define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c)))
typedef struct addr_policy_t addr_policy_t;
typedef struct cached_dir_t cached_dir_t;
/** Enum used to remember where a signed_descriptor_t is stored and how to
* manage the memory for signed_descriptor_body. */
typedef enum {
/** The descriptor isn't stored on disk at all: the copy in memory is
* canonical; the saved_offset field is meaningless. */
SAVED_NOWHERE=0,
/** The descriptor is stored in the cached_routers file: the
* signed_descriptor_body is meaningless; the signed_descriptor_len and
* saved_offset are used to index into the mmaped cache file. */
SAVED_IN_CACHE,
/** The descriptor is stored in the cached_routers.new file: the
* signed_descriptor_body and saved_offset fields are both set. */
/* FFFF (We could also mmap the file and grow the mmap as needed, or
* lazy-load the descriptor text by using seek and read. We don't, for
* now.)
*/
SAVED_IN_JOURNAL
} saved_location_t;
#define saved_location_bitfield_t ENUM_BF(saved_location_t)
/** Enumeration: what directory object is being downloaded?
* This determines which schedule is selected to perform the download. */
typedef enum {
DL_SCHED_GENERIC = 0,
DL_SCHED_CONSENSUS = 1,
DL_SCHED_BRIDGE = 2,
} download_schedule_t;
#define download_schedule_bitfield_t ENUM_BF(download_schedule_t)
/** Enumeration: is the download schedule for downloading from an authority,
* or from any available directory mirror?
* During bootstrap, "any" means a fallback (or an authority, if there
* are no fallbacks).
* When we have a valid consensus, "any" means any directory server. */
typedef enum {
DL_WANT_ANY_DIRSERVER = 0,
DL_WANT_AUTHORITY = 1,
} download_want_authority_t;
#define download_want_authority_bitfield_t \
ENUM_BF(download_want_authority_t)
/** Enumeration: do we want to increment the schedule position each time a
* connection is attempted (these attempts can be concurrent), or do we want
* to increment the schedule position after a connection fails? */
typedef enum {
DL_SCHED_INCREMENT_FAILURE = 0,
DL_SCHED_INCREMENT_ATTEMPT = 1,
} download_schedule_increment_t;
#define download_schedule_increment_bitfield_t \
ENUM_BF(download_schedule_increment_t)
typedef struct download_status_t download_status_t;
/** If n_download_failures is this high, the download can never happen. */
#define IMPOSSIBLE_TO_DOWNLOAD 255
/** The max size we expect router descriptor annotations we create to
* be. We'll accept larger ones if we see them on disk, but we won't
* create any that are larger than this. */
#define ROUTER_ANNOTATION_BUF_LEN 256
typedef struct signed_descriptor_t signed_descriptor_t;
/** Flags used to summarize the declared protocol versions of a relay,
* so we don't need to parse them again and again. */
typedef struct protover_summary_flags_t {
/** True iff we have a proto line for this router, or a versions line
* from which we could infer the protocols. */
unsigned int protocols_known:1;
/** True iff this router has a version or protocol list that allows it to
* accept EXTEND2 cells. This requires Relay=2. */
unsigned int supports_extend2_cells:1;
/** True iff this router has a version or protocol list that allows it to
* accept IPv6 connections. This requires Relay=2 or Relay=3. */
unsigned int supports_accepting_ipv6_extends:1;
/** True iff this router has a version or protocol list that allows it to
* initiate IPv6 connections. This requires Relay=3. */
unsigned int supports_initiating_ipv6_extends:1;
/** True iff this router has a version or protocol list that allows it to
* consider IPv6 connections canonical. This requires Relay=3. */
unsigned int supports_canonical_ipv6_conns:1;
/** True iff this router has a protocol list that allows it to negotiate
* ed25519 identity keys on a link handshake with us. This
* requires LinkAuth=3. */
unsigned int supports_ed25519_link_handshake_compat:1;
/** True iff this router has a protocol list that allows it to negotiate
* ed25519 identity keys on a link handshake, at all. This requires some
* LinkAuth=X for X >= 3. */
unsigned int supports_ed25519_link_handshake_any:1;
/** True iff this router has a protocol list that allows it to be an
* introduction point supporting ed25519 authentication key which is part of
* the v3 protocol detailed in proposal 224. This requires HSIntro=4. */
unsigned int supports_ed25519_hs_intro : 1;
/** True iff this router has a protocol list that allows it to support the
* ESTABLISH_INTRO DoS cell extension. Requires HSIntro=5. */
unsigned int supports_establish_intro_dos_extension : 1;
/** True iff this router has a protocol list that allows it to be an hidden
* service directory supporting version 3 as seen in proposal 224. This
* requires HSDir=2. */
unsigned int supports_v3_hsdir : 1;
/** True iff this router has a protocol list that allows it to be an hidden
* service rendezvous point supporting version 3 as seen in proposal 224.
* This requires HSRend=2. */
unsigned int supports_v3_rendezvous_point: 1;
/** True iff this router has a protocol list that allows clients to
* negotiate hs circuit setup padding. Requires Padding=2. */
unsigned int supports_hs_setup_padding : 1;
/** True iff this router supports congestion control.
* Requires both FlowCtrl=2 *and* Relay=4 */
unsigned int supports_congestion_control : 1;
/** True iff this router supports conflux. Requires Relay=5 */
unsigned int supports_conflux : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
typedef struct extrainfo_t extrainfo_t;
typedef struct routerstatus_t routerstatus_t;
typedef struct microdesc_t microdesc_t;
typedef struct node_t node_t;
typedef struct vote_microdesc_hash_t vote_microdesc_hash_t;
typedef struct vote_routerstatus_t vote_routerstatus_t;
typedef struct document_signature_t document_signature_t;
typedef struct networkstatus_voter_info_t networkstatus_voter_info_t;
typedef struct networkstatus_sr_info_t networkstatus_sr_info_t;
/** Enumerates recognized flavors of a consensus networkstatus document. All
* flavors of a consensus are generated from the same set of votes, but they
* present different types information to different versions of Tor. */
typedef enum {
FLAV_NS = 0,
FLAV_MICRODESC = 1,
} consensus_flavor_t;
/** How many different consensus flavors are there? */
#define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1)
typedef struct networkstatus_t networkstatus_t;
typedef struct ns_detached_signatures_t ns_detached_signatures_t;
typedef struct desc_store_t desc_store_t;
typedef struct routerlist_t routerlist_t;
typedef struct extend_info_t extend_info_t;
typedef struct authority_cert_t authority_cert_t;
/** Bitfield enum type listing types of information that directory authorities
* can be authoritative about, and that directory caches may or may not cache.
*
* Note that the granularity here is based on authority granularity and on
* cache capabilities. Thus, one particular bit may correspond in practice to
* a few types of directory info, so long as every authority that pronounces
* officially about one of the types prounounces officially about all of them,
* and so long as every cache that caches one of them caches all of them.
*/
typedef enum {
NO_DIRINFO = 0,
/** Serves/signs v3 directory information: votes, consensuses, certs */
V3_DIRINFO = 1 << 2,
/** Serves bridge descriptors. */
BRIDGE_DIRINFO = 1 << 4,
/** Serves extrainfo documents. */
EXTRAINFO_DIRINFO=1 << 5,
/** Serves microdescriptors. */
MICRODESC_DIRINFO=1 << 6,
} dirinfo_type_t;
#define ALL_DIRINFO ((dirinfo_type_t)((1<<7)-1))
#define ONION_HANDSHAKE_TYPE_TAP 0x0000
#define ONION_HANDSHAKE_TYPE_FAST 0x0001
#define ONION_HANDSHAKE_TYPE_NTOR 0x0002
#define ONION_HANDSHAKE_TYPE_NTOR_V3 0x0003
#define MAX_ONION_HANDSHAKE_TYPE 0x0003
typedef struct onion_handshake_state_t onion_handshake_state_t;
typedef struct relay_crypto_t relay_crypto_t;
typedef struct crypt_path_t crypt_path_t;
typedef struct crypt_path_reference_t crypt_path_reference_t;
#define CPATH_KEY_MATERIAL_LEN (20*2+16*2)
typedef struct cpath_build_state_t cpath_build_state_t;
struct create_cell_t;
/** Entry in the cell stats list of a circuit; used only if CELL_STATS
* events are enabled. */
typedef struct testing_cell_stats_entry_t {
uint8_t command; /**< cell command number. */
/** Waiting time in centiseconds if this event is for a removed cell,
* or 0 if this event is for adding a cell to the queue. 22 bits can
* store more than 11 hours, enough to assume that a circuit with this
* delay would long have been closed. */
unsigned int waiting_time:22;
unsigned int removed:1; /**< 0 for added to, 1 for removed from queue. */
unsigned int exitward:1; /**< 0 for app-ward, 1 for exit-ward. */
} testing_cell_stats_entry_t;
typedef struct circuit_t circuit_t;
typedef struct origin_circuit_t origin_circuit_t;
typedef struct or_circuit_t or_circuit_t;
/** Largest number of relay_early cells that we can send on a given
* circuit. */
#define MAX_RELAY_EARLY_CELLS_PER_CIRCUIT 8
typedef enum path_state_t path_state_t;
#define path_state_bitfield_t ENUM_BF(path_state_t)
#if REND_COOKIE_LEN != DIGEST_LEN
#error "The REND_TOKEN_LEN macro assumes REND_COOKIE_LEN == DIGEST_LEN"
#endif
#define REND_TOKEN_LEN DIGEST_LEN
/** Convert a circuit subtype to a circuit_t. */
#define TO_CIRCUIT(x) (&((x)->base_))
/** @name Isolation flags
Ways to isolate client streams
@{
*/
/** Isolate based on destination port */
#define ISO_DESTPORT (1u<<0)
/** Isolate based on destination address */
#define ISO_DESTADDR (1u<<1)
/** Isolate based on SOCKS authentication */
#define ISO_SOCKSAUTH (1u<<2)
/** Isolate based on client protocol choice */
#define ISO_CLIENTPROTO (1u<<3)
/** Isolate based on client address */
#define ISO_CLIENTADDR (1u<<4)
/** Isolate based on session group (always on). */
#define ISO_SESSIONGRP (1u<<5)
/** Isolate based on newnym epoch (always on). */
#define ISO_NYM_EPOCH (1u<<6)
/** Isolate all streams (Internal only). */
#define ISO_STREAM (1u<<7)
/**@}*/
/** Default isolation level for ports. */
#define ISO_DEFAULT (ISO_CLIENTADDR|ISO_SOCKSAUTH|ISO_SESSIONGRP|ISO_NYM_EPOCH)
/** Indicates that we haven't yet set a session group on a port_cfg_t. */
#define SESSION_GROUP_UNSET -1
/** Session group reserved for directory connections */
#define SESSION_GROUP_DIRCONN -2
/** Session group reserved for resolve requests launched by a controller */
#define SESSION_GROUP_CONTROL_RESOLVE -3
/** First automatically allocated session group number */
#define SESSION_GROUP_FIRST_AUTO -4
typedef struct port_cfg_t port_cfg_t;
typedef struct routerset_t routerset_t;
/** A magic value for the (Socks|OR|...)Port options below, telling Tor
* to pick its own port. */
#define CFG_AUTO_PORT 0xc4005e
typedef struct or_options_t or_options_t;
typedef struct or_state_t or_state_t;
#define MAX_SOCKS_ADDR_LEN 256
/********************************* circuitbuild.c **********************/
/** How many hops does a general-purpose circuit have by default? */
#define DEFAULT_ROUTE_LEN 3
/* Circuit Build Timeout "public" structures. */
/** Precision multiplier for the Bw weights */
#define BW_WEIGHT_SCALE 10000
#define BW_MIN_WEIGHT_SCALE 1
#define BW_MAX_WEIGHT_SCALE INT32_MAX
typedef struct circuit_build_times_t circuit_build_times_t;
/********************************* config.c ***************************/
/********************************* connection_edge.c *************************/
/** Enumerates possible origins of a client-side address mapping. */
typedef enum {
/** We're remapping this address because the controller told us to. */
ADDRMAPSRC_CONTROLLER,
/** We're remapping this address because of an AutomapHostsOnResolve
* configuration. */
ADDRMAPSRC_AUTOMAP,
/** We're remapping this address because our configuration (via torrc, the
* command line, or a SETCONF command) told us to. */
ADDRMAPSRC_TORRC,
/** We're remapping this address because we have TrackHostExit configured,
* and we want to remember to use the same exit next time. */
ADDRMAPSRC_TRACKEXIT,
/** We're remapping this address because we got a DNS resolution from a
* Tor server that told us what its value was. */
ADDRMAPSRC_DNS,
/** No remapping has occurred. This isn't a possible value for an
* addrmap_entry_t; it's used as a null value when we need to answer "Why
* did this remapping happen." */
ADDRMAPSRC_NONE
} addressmap_entry_source_t;
#define addressmap_entry_source_bitfield_t ENUM_BF(addressmap_entry_source_t)
#define WRITE_STATS_INTERVAL (24*60*60)
/********************************* dirvote.c ************************/
typedef struct vote_timing_t vote_timing_t;
/********************************* microdesc.c *************************/
typedef struct microdesc_cache_t microdesc_cache_t;
/** The maximum number of non-circuit-build-timeout failures a hidden
* service client will tolerate while trying to build a circuit to an
* introduction point. */
#define MAX_INTRO_POINT_REACHABILITY_FAILURES 5
/** The minimum and maximum number of distinct INTRODUCE2 cells which a
* hidden service's introduction point will receive before it begins to
* expire. */
#define INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS 16384
/* Double the minimum value so the interval is [min, min * 2]. */
#define INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS \
(INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS * 2)
/** The minimum number of seconds that an introduction point will last
* before expiring due to old age. (If it receives
* INTRO_POINT_LIFETIME_INTRODUCTIONS INTRODUCE2 cells, it may expire
* sooner.)
*
* XXX Should this be configurable? */
#define INTRO_POINT_LIFETIME_MIN_SECONDS (18*60*60)
/** The maximum number of seconds that an introduction point will last
* before expiring due to old age.
*
* XXX Should this be configurable? */
#define INTRO_POINT_LIFETIME_MAX_SECONDS (24*60*60)
/** The maximum number of circuit creation retry we do to an intro point
* before giving up. We try to reuse intro point that fails during their
* lifetime so this is a hard limit on the amount of time we do that. */
#define MAX_INTRO_POINT_CIRCUIT_RETRIES 3
/********************************* routerlist.c ***************************/
typedef struct dir_server_t dir_server_t;
#define RELAY_REQUIRED_MIN_BANDWIDTH (75*1024)
#define BRIDGE_REQUIRED_MIN_BANDWIDTH (50*1024)
#define ROUTER_MAX_DECLARED_BANDWIDTH INT32_MAX
typedef struct tor_version_t tor_version_t;
#endif /* !defined(TOR_OR_H) */
@@ -0,0 +1,107 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef OR_CIRCUIT_ST_H
#define OR_CIRCUIT_ST_H
#include "core/or/or.h"
#include "core/or/circuit_st.h"
#include "core/or/crypt_path_st.h"
#include "lib/evloop/token_bucket.h"
struct onion_queue_t;
/** An or_circuit_t holds information needed to implement a circuit at an
* OR. */
struct or_circuit_t {
circuit_t base_;
/** Pointer to an entry on the onion queue, if this circuit is waiting for a
* chance to give an onionskin to a cpuworker. Used only in onion.c */
struct onion_queue_t *onionqueue_entry;
/** Pointer to a workqueue entry, if this circuit has given an onionskin to
* a cpuworker and is waiting for a response. Used to decide whether it is
* safe to free a circuit or if it is still in use by a cpuworker. */
struct workqueue_entry_t *workqueue_entry;
/** The circuit_id used in the previous (backward) hop of this circuit. */
circid_t p_circ_id;
/** Queue of cells waiting to be transmitted on p_conn. */
cell_queue_t p_chan_cells;
/** The channel that is previous in this circuit. */
channel_t *p_chan;
/** Linked list of Exit streams associated with this circuit.
*
* Note that any updates to this pointer must be followed with
* conflux_update_n_streams() to keep the other legs n_streams
* in sync. */
edge_connection_t *n_streams;
/** Linked list of Exit streams associated with this circuit that are
* still being resolved.
*
* Just like with n_streams, any updates to this pointer must
* be followed with conflux_update_resolving_streams().
*/
edge_connection_t *resolving_streams;
/** Cryptographic state used for encrypting and authenticating relay
* cells to and from this hop. */
relay_crypto_t crypto;
/** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
* is not marked for close. */
struct or_circuit_t *rend_splice;
/** Stores KH for the handshake. */
char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */
/** Number of cells which we have discarded because of having no next hop,
* despite not recognizing the cell. */
uint32_t n_cells_discarded_at_end;
/** How many more relay_early cells can we send on this circuit, according
* to the specification? */
unsigned int remaining_relay_early_cells : 4;
/* We have already received an INTRODUCE1 cell on this circuit. */
unsigned int already_received_introduce1 : 1;
/** If set, this circuit carries HS traffic. Consider it in any HS
* statistics. */
unsigned int circuit_carries_hs_traffic_stats : 1;
/** True iff this circuit was made with a CREATE_FAST cell, or a CREATE[2]
* cell with a TAP handshake. If this is the case and this is a rend circuit,
* this is a v2 circuit, otherwise if this is a rend circuit it's a v3
* circuit. */
bool used_legacy_circuit_handshake;
/** Number of cells that were removed from circuit queue; reset every
* time when writing buffer stats to disk. */
uint32_t processed_cells;
/** Total time in milliseconds that cells spent in both app-ward and
* exit-ward queues of this circuit; reset every time when writing
* buffer stats to disk. */
uint64_t total_cell_waiting_time;
/** If set, the DoS defenses are enabled on this circuit meaning that the
* introduce2_bucket is initialized and used. */
unsigned int introduce2_dos_defense_enabled : 1;
/** If set, the DoS defenses were explicitly enabled through the
* ESTABLISH_INTRO cell extension. If unset, the consensus is used to learn
* if the defenses can be enabled or not. */
unsigned int introduce2_dos_defense_explicit : 1;
/** INTRODUCE2 cell bucket controlling how much can go on this circuit. Only
* used if this is a service introduction circuit at the intro point
* (purpose = CIRCUIT_PURPOSE_INTRO_POINT). */
token_bucket_ctr_t introduce2_bucket;
};
#endif /* !defined(OR_CIRCUIT_ST_H) */
@@ -0,0 +1,111 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file or_connection_st.h
* @brief OR connection structure.
**/
#ifndef OR_CONNECTION_ST_H
#define OR_CONNECTION_ST_H
#include "core/or/connection_st.h"
#include "lib/evloop/token_bucket.h"
struct tor_tls_t;
/** Subtype of connection_t for an "OR connection" -- that is, one that speaks
* cells over TLS. */
struct or_connection_t {
connection_t base_;
/** Hash of the public RSA key for the other side's identity key, or zeroes
* if the other side hasn't shown us a valid identity key. */
char identity_digest[DIGEST_LEN];
/** This is the ClientHash value we expect to receive from the
* client during the Extended ORPort authentication protocol. We
* compute it upon receiving the ClientNonce from the client, and we
* compare it with the actual ClientHash value sent by the
* client. */
char *ext_or_auth_correct_client_hash;
/** String carrying the name of the pluggable transport
* (e.g. "obfs2") that is obfuscating this connection. If no
* pluggable transports are used, it's NULL. */
char *ext_or_transport;
char *nickname; /**< Nickname of OR on other side (if any). */
struct tor_tls_t *tls; /**< TLS connection state. */
int tls_error; /**< Last tor_tls error code. */
/** When we last used this conn for any client traffic. If not
* recent, we can rate limit it further. */
/* Channel using this connection */
channel_tls_t *chan;
/**
* The "canonical" address and port for this relay's ORPort, if this is
* a known relay.
*
* An ORPort is "canonical" in this sense only if it is the same ORPort
* that is listed for this identity in the consensus we have.
*
* This field may be set on outbound connections for _any_ relay, and on
* inbound connections after authentication. If we don't know the relay's
* identity, or if we don't have the relay's identity in our consensus, we
* leave this address as UNSPEC.
**/
tor_addr_port_t canonical_orport;
/** Should this connection be used for extending circuits to the server
* matching the <b>identity_digest</b> field? Set to true if we're pretty
* sure we aren't getting MITMed, either because we're connected to an
* address listed in a server descriptor, or because an authenticated
* NETINFO cell listed the address we're connected to as recognized. */
unsigned int is_canonical:1;
/** True iff this is an outgoing connection. */
unsigned int is_outgoing:1;
unsigned int proxy_type:3; /**< One of PROXY_NONE...PROXY_HAPROXY */
unsigned int wide_circ_ids:1;
/** True iff a failure on this connection indicates a possible
* bootstrapping problem. We set this as true if we notice that this
* connection could handle a pending origin circuit, or if we launch it to
* handle an origin circuit. */
unsigned int potentially_used_for_bootstrapping:1;
/** True iff this connection has had its bootstrap failure logged with
* control_event_bootstrap_problem. */
unsigned int have_noted_bootstrap_problem:1;
/** True iff this is a client connection and its address has been put in the
* geoip cache and handled by the DoS mitigation subsystem. We use this to
* insure we have a coherent count of concurrent connection. */
unsigned int tracked_for_dos_mitigation : 1;
/** True iff this connection is using a pluggable transport */
unsigned int is_pt : 1;
uint16_t link_proto; /**< What protocol version are we using? 0 for
* "none negotiated yet." */
uint16_t idle_timeout; /**< How long can this connection sit with no
* circuits on it before we close it? Based on
* IDLE_CIRCUIT_TIMEOUT_{NON,}CANONICAL and
* on is_canonical, randomized. */
or_handshake_state_t *handshake_state; /**< If we are setting this connection
* up, state information to do so. */
time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/
token_bucket_rw_t bucket; /**< Used for rate limiting when the connection is
* in state CONN_OPEN. */
/*
* Count the number of bytes flushed out on this orconn, and the number of
* bytes TLS actually sent - used for overhead estimation for scheduling.
*/
uint64_t bytes_xmitted, bytes_xmitted_by_tls;
};
#endif /* !defined(OR_CONNECTION_ST_H) */
@@ -0,0 +1,45 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file or_handshake_certs_st.h
* @brief OR handshake certs structure
**/
#ifndef OR_HANDSHAKE_CERTS_ST
#define OR_HANDSHAKE_CERTS_ST
struct tor_x509_cert_t;
/** Structure to hold all the certificates we've received on an OR connection
*/
struct or_handshake_certs_t {
/** True iff we originated this connection. */
int started_here;
/** The cert for the 'auth' RSA key that's supposed to sign the AUTHENTICATE
* cell. Signed with the RSA identity key. */
struct tor_x509_cert_t *auth_cert;
/** The cert for the 'link' RSA key that was used to negotiate the TLS
* connection. Signed with the RSA identity key. */
struct tor_x509_cert_t *link_cert;
/** A self-signed identity certificate: the RSA identity key signed
* with itself. */
struct tor_x509_cert_t *id_cert;
/** The Ed25519 signing key, signed with the Ed25519 identity key. */
struct tor_cert_st *ed_id_sign;
/** A digest of the X509 link certificate for the TLS connection, signed
* with the Ed25519 siging key. */
struct tor_cert_st *ed_sign_link;
/** The Ed25519 authentication key (that's supposed to sign an AUTHENTICATE
* cell) , signed with the Ed25519 siging key. */
struct tor_cert_st *ed_sign_auth;
/** The Ed25519 identity key, crosssigned with the RSA identity key. */
uint8_t *ed_rsa_crosscert;
/** The length of <b>ed_rsa_crosscert</b> in bytes */
size_t ed_rsa_crosscert_len;
};
#endif /* !defined(OR_HANDSHAKE_CERTS_ST) */
@@ -0,0 +1,82 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file or_handshake_state_st.h
* @brief OR handshake state structure
**/
#ifndef OR_HANDSHAKE_STATE_ST
#define OR_HANDSHAKE_STATE_ST
/** Stores flags and information related to the portion of a v2/v3 Tor OR
* connection handshake that happens after the TLS handshake is finished.
*/
struct or_handshake_state_t {
/** When was the VERSIONS cell sent on this connection? Used to get
* an estimate of the skew in the returning NETINFO reply. */
time_t sent_versions_at;
/** True iff we originated this connection */
unsigned int started_here : 1;
/** True iff we have received and processed a VERSIONS cell. */
unsigned int received_versions : 1;
/** True iff we have received and processed an AUTH_CHALLENGE cell */
unsigned int received_auth_challenge : 1;
/** True iff we have received and processed a CERTS cell. */
unsigned int received_certs_cell : 1;
/** True iff we have received and processed an AUTHENTICATE cell */
unsigned int received_authenticate : 1;
/* True iff we've received valid authentication to some identity. */
unsigned int authenticated : 1;
unsigned int authenticated_rsa : 1;
unsigned int authenticated_ed25519 : 1;
/* True iff we have sent a netinfo cell */
unsigned int sent_netinfo : 1;
/** The signing->ed25519 link certificate corresponding to the x509
* certificate we used on the TLS connection (if this is a server-side
* connection). We make a copy of this here to prevent a race condition
* caused by TLS context rotation. */
struct tor_cert_st *own_link_cert;
/** True iff we should feed outgoing cells into digest_sent and
* digest_received respectively.
*
* From the server's side of the v3 handshake, we want to capture everything
* from the VERSIONS cell through and including the AUTH_CHALLENGE cell.
* From the client's, we want to capture everything from the VERSIONS cell
* through but *not* including the AUTHENTICATE cell.
*
* @{ */
unsigned int digest_sent_data : 1;
unsigned int digest_received_data : 1;
/**@}*/
/** Identity RSA digest that we have received and authenticated for our peer
* on this connection. */
uint8_t authenticated_rsa_peer_id[DIGEST_LEN];
/** Identity Ed25519 public key that we have received and authenticated for
* our peer on this connection. */
ed25519_public_key_t authenticated_ed25519_peer_id;
/** Digests of the cells that we have sent or received as part of a V3
* handshake. Used for making and checking AUTHENTICATE cells.
*
* @{
*/
crypto_digest_t *digest_sent;
crypto_digest_t *digest_received;
/** @} */
/** Certificates that a connection initiator sent us in a CERTS cell; we're
* holding on to them until we get an AUTHENTICATE cell.
*/
or_handshake_certs_t *certs;
};
#endif /* !defined(OR_HANDSHAKE_STATE_ST) */
@@ -0,0 +1,17 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file or_periodic.h
* @brief Header for core/or/or_periodic.c
**/
#ifndef TOR_CORE_OR_OR_PERIODIC_H
#define TOR_CORE_OR_OR_PERIODIC_H
void or_register_periodic_events(void);
#endif /* !defined(TOR_CORE_OR_OR_PERIODIC_H) */
@@ -0,0 +1,21 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file or_sys.h
* @brief Header for core/or/or_sys.c
**/
#ifndef TOR_CORE_OR_OR_SYS_H
#define TOR_CORE_OR_OR_SYS_H
extern const struct subsys_fns_t sys_or;
struct pubsub_connector_t;
int ocirc_add_pubsub(struct pubsub_connector_t *connector);
int orconn_add_pubsub(struct pubsub_connector_t *connector);
#endif /* !defined(TOR_CORE_OR_OR_SYS_H) */
@@ -0,0 +1,103 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file orconn_event.h
* \brief Header file for orconn_event.c
*
* The OR_CONN_STATE_* symbols are here to make it easier for
* subscribers to make decisions based on the messages that they
* receive.
**/
#ifndef TOR_ORCONN_EVENT_H
#define TOR_ORCONN_EVENT_H
#include "lib/pubsub/pubsub.h"
/**
* @name States of OR connections
*
* These must be in a partial ordering such that usually no OR
* connection will transition from a higher-numbered state to a
* lower-numbered one. Code such as bto_update_best() depends on this
* ordering to determine the best state it's seen so far.
* @{ */
#define OR_CONN_STATE_MIN_ 1
/** State for a connection to an OR: waiting for connect() to finish. */
#define OR_CONN_STATE_CONNECTING 1
/** State for a connection to an OR: waiting for proxy handshake to complete */
#define OR_CONN_STATE_PROXY_HANDSHAKING 2
/** State for an OR connection client: SSL is handshaking, not done
* yet. */
#define OR_CONN_STATE_TLS_HANDSHAKING 3
/** State for a connection to an OR: We're doing a second SSL handshake for
* renegotiation purposes. (V2 handshake only.) */
#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4
/** State for a connection at an OR: We're waiting for the client to
* renegotiate (to indicate a v2 handshake) or send a versions cell (to
* indicate a v3 handshake) */
#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5
/** State for an OR connection: We're done with our SSL handshake, we've done
* renegotiation, but we haven't yet negotiated link protocol versions and
* sent a netinfo cell. */
#define OR_CONN_STATE_OR_HANDSHAKING_V2 6
/** State for an OR connection: We're done with our SSL handshake, but we
* haven't yet negotiated link protocol versions, done a V3 handshake, and
* sent a netinfo cell. */
#define OR_CONN_STATE_OR_HANDSHAKING_V3 7
/** State for an OR connection: Ready to send/receive cells. */
#define OR_CONN_STATE_OPEN 8
#define OR_CONN_STATE_MAX_ 8
/** @} */
/** Used to indicate the type of an OR connection event passed to the
* controller. The various types are defined in control-spec.txt */
typedef enum or_conn_status_event_t {
OR_CONN_EVENT_LAUNCHED = 0,
OR_CONN_EVENT_CONNECTED = 1,
OR_CONN_EVENT_FAILED = 2,
OR_CONN_EVENT_CLOSED = 3,
OR_CONN_EVENT_NEW = 4,
} or_conn_status_event_t;
/**
* Message for orconn state update
*
* This contains information about internal state changes of
* or_connection_t objects. The chan and proxy_type fields are
* additional information that a subscriber may need to make
* decisions.
**/
typedef struct orconn_state_msg_t {
uint64_t gid; /**< connection's global ID */
uint64_t chan; /**< associated channel ID */
int proxy_type; /**< connection's proxy type */
uint8_t state; /**< new connection state */
} orconn_state_msg_t;
DECLARE_MESSAGE(orconn_state, orconn_state, orconn_state_msg_t *);
/**
* Message for orconn status event
*
* This contains information that ends up in ORCONN control protocol
* events.
**/
typedef struct orconn_status_msg_t {
uint64_t gid; /**< connection's global ID */
int status; /**< or_conn_status_event_t */
int reason; /**< reason */
} orconn_status_msg_t;
DECLARE_MESSAGE(orconn_status, orconn_status, orconn_status_msg_t *);
#ifdef ORCONN_EVENT_PRIVATE
void orconn_state_publish(orconn_state_msg_t *);
void orconn_status_publish(orconn_status_msg_t *);
#endif
#endif /* !defined(TOR_ORCONN_EVENT_H) */
@@ -0,0 +1,315 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file origin_circuit_st.h
* @brief Origin circuit structure.
**/
#ifndef ORIGIN_CIRCUIT_ST_H
#define ORIGIN_CIRCUIT_ST_H
#include "core/or/or.h"
#include "core/or/circuit_st.h"
struct onion_queue_t;
/**
* Describes the circuit building process in simplified terms based
* on the path bias accounting state for a circuit.
*
* NOTE: These state values are enumerated in the order for which we
* expect circuits to transition through them. If you add states,
* you need to preserve this overall ordering. The various pathbias
* state transition and accounting functions (pathbias_mark_* and
* pathbias_count_*) contain ordinal comparisons to enforce proper
* state transitions for corrections.
*
* This state machine and the associated logic was created to prevent
* miscounting due to unknown cases of circuit reuse. See also tickets
* #6475 and #7802.
*/
enum path_state_t {
/** This circuit is "new". It has not yet completed a first hop
* or been counted by the path bias code. */
PATH_STATE_NEW_CIRC = 0,
/** This circuit has completed one/two hops, and has been counted by
* the path bias logic. */
PATH_STATE_BUILD_ATTEMPTED = 1,
/** This circuit has been completely built */
PATH_STATE_BUILD_SUCCEEDED = 2,
/** Did we try to attach any SOCKS streams or hidserv introductions to
* this circuit?
*
* Note: If we ever implement end-to-end stream timing through test
* stream probes (#5707), we must *not* set this for those probes
* (or any other automatic streams) because the adversary could
* just tag at a later point.
*/
PATH_STATE_USE_ATTEMPTED = 3,
/** Did any SOCKS streams or hidserv introductions actually succeed on
* this circuit?
*
* If any streams detach/fail from this circuit, the code transitions
* the circuit back to PATH_STATE_USE_ATTEMPTED to ensure we probe. See
* pathbias_mark_use_rollback() for that.
*/
PATH_STATE_USE_SUCCEEDED = 4,
/**
* This is a special state to indicate that we got a corrupted
* relay cell on a circuit and we don't intend to probe it.
*/
PATH_STATE_USE_FAILED = 5,
/**
* This is a special state to indicate that we already counted
* the circuit. Used to guard against potential state machine
* violations.
*/
PATH_STATE_ALREADY_COUNTED = 6,
};
/** An origin_circuit_t holds data necessary to build and use a circuit.
*/
struct origin_circuit_t {
circuit_t base_;
/** Linked list of AP streams (or EXIT streams if hidden service)
* associated with this circuit.
*
* Any updates to this pointer must be followed with
* conflux_update_p_streams(). */
edge_connection_t *p_streams;
/** Smartlist of half-closed streams (half_edge_t*) that still
* have pending activity.
*
* Any updates to this pointer must be followed with
* conflux_update_half_streams().
*/
smartlist_t *half_streams;
/** Bytes read on this circuit since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_read_circ_bw;
/** Bytes written to on this circuit since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_written_circ_bw;
/** Total known-valid relay cell bytes since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_delivered_read_circ_bw;
/** Total written relay cell bytes since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_delivered_written_circ_bw;
/** Total overhead data in all known-valid relay data cells since last
* call to control_event_circ_bandwidth_used(). Only used if we're
* configured to emit CIRC_BW events. */
uint32_t n_overhead_read_circ_bw;
/** Total written overhead data in all relay data cells since last call to
* control_event_circ_bandwidth_used(). Only used if we're configured
* to emit CIRC_BW events. */
uint32_t n_overhead_written_circ_bw;
/** Build state for this circuit. It includes the intended path
* length, the chosen exit router, rendezvous information, etc.
*/
cpath_build_state_t *build_state;
/** The doubly-linked list of crypt_path_t entries, one per hop,
* for this circuit. This includes ciphers for each hop,
* integrity-checking digests for each hop, and package/delivery
* windows for each hop.
*/
crypt_path_t *cpath;
/** Holds hidden service identifier on either client or service side. This
* is for both introduction and rendezvous circuit. */
struct hs_ident_circuit_t *hs_ident;
/** Holds the data that the entry guard system uses to track the
* status of the guard this circuit is using, and thereby to determine
* whether this circuit can be used. */
struct circuit_guard_state_t *guard_state;
/** Index into global_origin_circuit_list for this circuit. -1 if not
* present. */
int global_origin_circuit_list_idx;
/** How many more relay_early cells can we send on this circuit, according
* to the specification? */
unsigned int remaining_relay_early_cells : 4;
/** Set if this circuit is insanely old and we already informed the user */
unsigned int is_ancient : 1;
/** Set if this circuit has already been opened. Used to detect
* cannibalized circuits. */
unsigned int has_opened : 1;
/**
* Path bias state machine. Used to ensure integrity of our
* circuit building and usage accounting. See path_state_t
* for more details.
*/
path_state_bitfield_t path_state : 3;
/* If this flag is set, we should not consider attaching any more
* connections to this circuit. */
unsigned int unusable_for_new_conns : 1;
/* If this flag is set (due to padding negotiation failure), we should
* not try to negotiate further circuit padding. */
unsigned padding_negotiation_failed : 1;
/**
* If this flag is set, then a controller chose the first hop of this
* circuit's path, and it's okay to ignore checks that we'd usually do
* on this circuit's first hop.
*
* This flag is distinct from the CIRCUIT_PURPOSE_CONTROLLER purpose: the
* purpose indicates _what tor can use the circuit for_. Controller-created
* circuits can still have the CIRCUIT_PURPOSE_GENERAL purpose if Tor is
* allowed to attach streams to them.
*/
unsigned first_hop_from_controller : 1;
/**
* If true, this circuit's path has been chosen, in full or in part,
* by the controller API, and it's okay to ignore checks that we'd
* usually do on the path as whole. */
unsigned int any_hop_from_controller : 1;
/**
* Tristate variable to guard against pathbias miscounting
* due to circuit purpose transitions changing the decision
* of pathbias_should_count(). This variable is informational
* only. The current results of pathbias_should_count() are
* the official decision for pathbias accounting.
*/
uint8_t pathbias_shouldcount;
#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0
#define PATHBIAS_SHOULDCOUNT_IGNORED 1
#define PATHBIAS_SHOULDCOUNT_COUNTED 2
/** For path probing. Store the temporary probe stream ID
* for response comparison */
streamid_t pathbias_probe_id;
/** For path probing. Store the temporary probe address nonce
* (in host byte order) for response comparison. */
uint32_t pathbias_probe_nonce;
/** This is nonzero iff hs_with_pow_circ is set and there was a valid proof
* of work solution associated with this circuit. */
uint32_t hs_pow_effort;
/** Set iff this is a hidden-service circuit for a HS with PoW defenses
* enabled, so that we know to be more lenient with timing out the
* circuit-build to allow the service time to work through the queue of
* requests. */
unsigned int hs_with_pow_circ : 1;
/** Set iff this intro circ required a pow, and it has already queued
* the pow with the cpuworker and is awaiting a reply. */
unsigned int hs_currently_solving_pow : 1;
/** Set iff this circuit has been given a relaxed timeout because
* no circuits have opened. Used to prevent spamming logs. */
unsigned int relaxed_timeout : 1;
/** What commands were sent over this circuit that decremented the
* RELAY_EARLY counter? This is for debugging task 878. */
uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT];
/** How many RELAY_EARLY cells have been sent over this circuit? This is
* for debugging task 878, too. */
int relay_early_cells_sent;
/** The next stream_id that will be tried when we're attempting to
* construct a new AP stream originating at this circuit. */
streamid_t next_stream_id;
/* The intro key replaces the hidden service's public key if purpose is
* S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous
* descriptor is used. */
crypto_pk_t *intro_key;
/** Quasi-global identifier for this circuit; used for control.c */
/* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier;
/** True if we have associated one stream to this circuit, thereby setting
* the isolation parameters for this circuit. Note that this doesn't
* necessarily mean that we've <em>attached</em> any streams to the circuit:
* we may only have marked up this circuit during the launch process.
*/
unsigned int isolation_values_set : 1;
/** True iff any stream has <em>ever</em> been attached to this circuit.
*
* In a better world we could use timestamp_dirty for this, but
* timestamp_dirty is far too overloaded at the moment.
*/
unsigned int isolation_any_streams_attached : 1;
/** A bitfield of ISO_* flags for every isolation field such that this
* circuit has had streams with more than one value for that field
* attached to it. */
uint8_t isolation_flags_mixed;
/** @name Isolation parameters
*
* If any streams have been associated with this circ (isolation_values_set
* == 1), and all streams associated with the circuit have had the same
* value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these
* elements hold the value for that field.
*
* Note again that "associated" is not the same as "attached": we
* preliminarily associate streams with a circuit while the circuit is being
* launched, so that we can tell whether we need to launch more circuits.
*
* @{
*/
uint8_t client_proto_type;
uint8_t client_proto_socksver;
uint16_t dest_port;
tor_addr_t client_addr;
char *dest_address;
int session_group;
unsigned nym_epoch;
size_t socks_username_len;
uint8_t socks_password_len;
/* Note that the next two values are NOT NUL-terminated; see
socks_username_len and socks_password_len for their lengths. */
char *socks_username;
char *socks_password;
/** Global identifier for the first stream attached here; used by
* ISO_STREAM. */
uint64_t associated_isolated_stream_global_id;
/**@}*/
/** A list of addr_policy_t for this circuit in particular. Used by
* adjust_exit_policy_from_exitpolicy_failure.
*/
smartlist_t *prepend_policy;
/** How long do we wait before closing this circuit if it remains
* completely idle after it was built, in seconds? This value
* is randomized on a per-circuit basis from CircuitsAvailableTimoeut
* to 2*CircuitsAvailableTimoeut. */
int circuit_idle_timeout;
};
#endif /* !defined(ORIGIN_CIRCUIT_ST_H) */
@@ -0,0 +1,192 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file policies.h
* \brief Header file for policies.c.
**/
#ifndef TOR_POLICIES_H
#define TOR_POLICIES_H
/* (length of
* "accept6 [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]/128:65535-65535\n"
* plus a terminating NUL, rounded up to a nice number.)
*/
#define POLICY_BUF_LEN 72
#define EXIT_POLICY_IPV6_ENABLED (1 << 0)
#define EXIT_POLICY_REJECT_PRIVATE (1 << 1)
#define EXIT_POLICY_ADD_DEFAULT (1 << 2)
#define EXIT_POLICY_REJECT_LOCAL_INTERFACES (1 << 3)
#define EXIT_POLICY_ADD_REDUCED (1 << 4)
#define EXIT_POLICY_OPTION_MAX EXIT_POLICY_ADD_REDUCED
/* All options set: used for unit testing */
#define EXIT_POLICY_OPTION_ALL ((EXIT_POLICY_OPTION_MAX << 1) - 1)
typedef enum firewall_connection_t {
FIREWALL_OR_CONNECTION = 0,
FIREWALL_DIR_CONNECTION = 1
} firewall_connection_t;
typedef int exit_policy_parser_cfg_t;
/** Outcome of applying an address policy to an address. */
typedef enum {
/** The address was accepted */
ADDR_POLICY_ACCEPTED=0,
/** The address was rejected */
ADDR_POLICY_REJECTED=-1,
/** Part of the address was unknown, but as far as we can tell, it was
* accepted. */
ADDR_POLICY_PROBABLY_ACCEPTED=1,
/** Part of the address was unknown, but as far as we can tell, it was
* rejected. */
ADDR_POLICY_PROBABLY_REJECTED=2,
} addr_policy_result_t;
/** A single entry in a parsed policy summary, describing a range of ports. */
typedef struct short_policy_entry_t {
uint16_t min_port, max_port;
} short_policy_entry_t;
/** A short_poliy_t is the parsed version of a policy summary. */
typedef struct short_policy_t {
/** True if the members of 'entries' are port ranges to accept; false if
* they are port ranges to reject */
unsigned int is_accept : 1;
/** The actual number of values in 'entries'. */
unsigned int n_entries : 31;
/** An array of 0 or more short_policy_entry_t values, each describing a
* range of ports that this policy accepts or rejects (depending on the
* value of is_accept).
*/
short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER];
} short_policy_t;
int firewall_is_fascist_or(void);
int firewall_is_fascist_dir(void);
int reachable_addr_use_ipv6(const or_options_t *options);
int reachable_addr_prefer_ipv6_orport(const or_options_t *options);
int reachable_addr_prefer_ipv6_dirport(const or_options_t *options);
int reachable_addr_allows_addr(const tor_addr_t *addr,
uint16_t port,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6);
int reachable_addr_allows_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only);
int reachable_addr_allows_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only);
int reachable_addr_allows_dir_server(const dir_server_t *ds,
firewall_connection_t fw_connection,
int pref_only);
void reachable_addr_choose_from_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
void reachable_addr_choose_from_ls(const smartlist_t *lspecs,
int pref_only, tor_addr_port_t* ap);
void reachable_addr_choose_from_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
void reachable_addr_choose_from_dir_server(const dir_server_t *ds,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
int dir_policy_permits_address(const tor_addr_t *addr);
int socks_policy_permits_address(const tor_addr_t *addr);
int metrics_policy_permits_address(const tor_addr_t *addr);
int authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port);
int authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port);
int authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port);
int authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port);
int policy_using_default_exit_options(const or_options_t *or_options);
int validate_addr_policies(const or_options_t *options, char **msg);
void policy_expand_private(smartlist_t **policy);
void policy_expand_unspec(smartlist_t **policy);
int policies_parse_from_options(const or_options_t *options);
addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
int addr_policies_eq(const smartlist_t *a, const smartlist_t *b);
MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
(const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
uint16_t port, const node_t *node);
int policies_parse_exit_policy_from_options(
const or_options_t *or_options,
const tor_addr_t *ipv4_local_address,
const tor_addr_t *ipv6_local_address,
smartlist_t **result);
struct config_line_t;
int policies_parse_exit_policy(struct config_line_t *cfg, smartlist_t **dest,
exit_policy_parser_cfg_t options,
const smartlist_t *configured_addresses);
void policies_parse_exit_policy_reject_private(
smartlist_t **dest,
int ipv6_exit,
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses);
void policies_exit_policy_append_reject_star(smartlist_t **dest);
void addr_policy_append_reject_addr(smartlist_t **dest,
const tor_addr_t *addr);
void addr_policy_append_reject_addr_list(smartlist_t **dest,
const smartlist_t *addrs);
void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter);
int exit_policy_is_general_exit(smartlist_t *policy);
int policy_is_reject_star(const smartlist_t *policy, sa_family_t family,
int reject_by_default);
char * policy_dump_to_string(const smartlist_t *policy_list,
int include_ipv4,
int include_ipv6);
int getinfo_helper_policies(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
int policy_write_item(char *buf, size_t buflen, const addr_policy_t *item,
int format_for_desc);
void addr_policy_list_free_(smartlist_t *p);
#define addr_policy_list_free(lst) \
FREE_AND_NULL(smartlist_t, addr_policy_list_free_, (lst))
void addr_policy_free_(addr_policy_t *p);
#define addr_policy_free(p) \
FREE_AND_NULL(addr_policy_t, addr_policy_free_, (p))
void policies_free_all(void);
char *policy_summarize(smartlist_t *policy, sa_family_t family);
short_policy_t *parse_short_policy(const char *summary);
char *write_short_policy(const short_policy_t *policy);
void short_policy_free_(short_policy_t *policy);
#define short_policy_free(p) \
FREE_AND_NULL(short_policy_t, short_policy_free_, (p))
int short_policy_is_reject_star(const short_policy_t *policy);
addr_policy_result_t compare_tor_addr_to_short_policy(
const tor_addr_t *addr, uint16_t port,
const short_policy_t *policy);
#ifdef POLICIES_PRIVATE
STATIC void append_exit_policy_string(smartlist_t **policy, const char *more);
STATIC int reachable_addr_allows(const tor_addr_t *addr,
uint16_t port,
smartlist_t *firewall_policy,
int pref_only, int pref_ipv6);
STATIC const tor_addr_port_t * reachable_addr_choose(
const tor_addr_port_t *a,
const tor_addr_port_t *b,
int want_a,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6);
#endif /* defined(POLICIES_PRIVATE) */
#endif /* !defined(TOR_POLICIES_H) */
@@ -0,0 +1,41 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file port_cfg_st.h
* @brief Listener port configuration structure.
**/
#ifndef PORT_CFG_ST_H
#define PORT_CFG_ST_H
#include "core/or/entry_port_cfg_st.h"
#include "core/or/server_port_cfg_st.h"
/** Configuration for a single port that we're listening on. */
struct port_cfg_t {
tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */
int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its
* own port. */
uint8_t type; /**< One of CONN_TYPE_*_LISTENER */
unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */
unsigned is_group_writable : 1;
unsigned is_world_writable : 1;
unsigned relax_dirmode_check : 1;
unsigned explicit_addr : 1; /** Indicate if address was explicitly set or
* we are using the default address. */
entry_port_cfg_t entry_cfg;
server_port_cfg_t server_cfg;
/* Unix sockets only: */
/** Path for an AF_UNIX address */
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
};
#endif /* !defined(PORT_CFG_ST_H) */
@@ -0,0 +1,128 @@
/* Copyright (c) 2016-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file protover.h
* \brief Headers and type declarations for protover.c
**/
#ifndef TOR_PROTOVER_H
#define TOR_PROTOVER_H
#include <stdbool.h>
#include "lib/cc/torint.h"
#include "lib/testsupport/testsupport.h"
struct smartlist_t;
/** The first version of Tor that included "proto" entries in its
* descriptors. Authorities should use this to decide whether to
* guess proto lines. */
/* This is a guess. */
/// C_RUST_COUPLED: src/rust/protover/protover.rs
/// `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
#define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS "0.2.9.3-alpha"
/** The protover version number that signifies ed25519 link handshake support
*/
#define PROTOVER_LINKAUTH_ED25519_HANDSHAKE 3
/** The protover version number that signifies extend2 cell support */
#define PROTOVER_RELAY_EXTEND2 2
/** The protover version number where relays can accept IPv6 connections */
#define PROTOVER_RELAY_ACCEPT_IPV6 2
/** The protover version number where relays can initiate IPv6 extends */
#define PROTOVER_RELAY_EXTEND_IPV6 3
/** The protover version number where relays can consider IPv6 connections
* canonical */
#define PROTOVER_RELAY_CANONICAL_IPV6 3
/** The protover version number where relays can accept ntorv3 */
#define PROTOVER_RELAY_NTOR_V3 4
/** The protover that signals conflux support. */
#define PROTOVER_CONFLUX_V1 1
/** The protover version number that signifies HSv3 intro point support */
#define PROTOVER_HS_INTRO_V3 4
/** The protover version number where intro points support denial of service
* resistance */
#define PROTOVER_HS_INTRO_DOS 5
/** The protover version number that signifies HSv3 rendezvous point support */
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
/** The protover version number that signifies HSDir support for HSv3 */
#define PROTOVER_HSDIR_V3 2
/** The protover that signals support for HS circuit setup padding machines */
#define PROTOVER_HS_SETUP_PADDING 2
/** The protover that signals support for congestion control */
#define PROTOVER_FLOWCTRL_CC 2
/** List of recognized subprotocols. */
/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust`
/// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto`
typedef enum protocol_type_t {
PRT_LINK = 0,
PRT_LINKAUTH = 1,
PRT_RELAY = 2,
PRT_DIRCACHE = 3,
PRT_HSDIR = 4,
PRT_HSINTRO = 5,
PRT_HSREND = 6,
PRT_DESC = 7,
PRT_MICRODESC = 8,
PRT_CONS = 9,
PRT_PADDING = 10,
PRT_FLOWCTRL = 11,
PRT_CONFLUX = 12,
} protocol_type_t;
bool protover_list_is_invalid(const char *s);
const char *protover_get_supported(const protocol_type_t type);
int protover_all_supported(const char *s, char **missing);
int protover_is_supported_here(protocol_type_t pr, uint32_t ver);
const char *protover_get_supported_protocols(void);
const char *protover_get_recommended_client_protocols(void);
const char *protover_get_recommended_relay_protocols(void);
const char *protover_get_required_client_protocols(void);
const char *protover_get_required_relay_protocols(void);
char *protover_compute_vote(const struct smartlist_t *list_of_proto_strings,
int threshold);
const char *protover_compute_for_old_tor(const char *version);
int protocol_list_supports_protocol(const char *list, protocol_type_t tp,
uint32_t version);
int protocol_list_supports_protocol_or_later(const char *list,
protocol_type_t tp,
uint32_t version);
void protover_free_all(void);
#ifdef PROTOVER_PRIVATE
/** Represents a set of ranges of subprotocols of a given type. */
typedef struct proto_entry_t {
/** The name of the protocol.
*
* (This needs to handle voting on protocols which
* we don't recognize yet, so it's a char* rather than a protocol_type_t.)
*/
char *name;
/** Bitmask of supported protocols. Version 'x' is included in this
* entry if and only if bit '1<<x' is set here. */
uint64_t bitmask;
} proto_entry_t;
#if defined(TOR_UNIT_TESTS)
STATIC struct smartlist_t *parse_protocol_list(const char *s);
STATIC char *encode_protocol_list(const struct smartlist_t *sl);
STATIC const char *protocol_type_to_str(protocol_type_t pr);
STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out);
STATIC void proto_entry_free_(proto_entry_t *entry);
#endif /* defined(TOR_UNIT_TESTS) */
#define proto_entry_free(entry) \
FREE_AND_NULL(proto_entry_t, proto_entry_free_, (entry))
#endif /* defined(PROTOVER_PRIVATE) */
#endif /* !defined(TOR_PROTOVER_H) */
@@ -0,0 +1,34 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file reasons.h
* \brief Header file for reasons.c.
**/
#ifndef TOR_REASONS_H
#define TOR_REASONS_H
#include "lib/net/socks5_status.h"
enum bandwidth_weight_rule_t;
const char *stream_end_reason_to_control_string(int reason);
const char *stream_end_reason_to_string(int reason);
socks5_reply_status_t stream_end_reason_to_socks5_response(int reason);
uint8_t errno_to_stream_end_reason(int e);
const char *orconn_end_reason_to_control_string(int r);
int tls_error_to_orconn_end_reason(int e);
int errno_to_orconn_end_reason(int e);
const char *circuit_end_reason_to_control_string(int reason);
const char *socks4_response_code_to_string(uint8_t code);
const char *socks5_response_code_to_string(uint8_t code);
const char *bandwidth_weight_rule_to_string(enum bandwidth_weight_rule_t rule);
const char *end_reason_to_http_connect_response_line(int endreason);
#endif /* !defined(TOR_REASONS_H) */
@@ -0,0 +1,147 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file relay.h
* \brief Header file for relay.c.
**/
#ifndef TOR_RELAY_H
#define TOR_RELAY_H
extern uint64_t stats_n_relay_cells_relayed;
extern uint64_t stats_n_relay_cells_delivered;
extern uint64_t stats_n_circ_max_cell_reached;
extern uint64_t stats_n_circ_max_cell_outq_reached;
const char *relay_command_to_string(uint8_t command);
void relay_consensus_has_changed(const networkstatus_t *ns);
uint32_t relay_get_param_max_circuit_cell_queue_size(
const networkstatus_t *ns);
int circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction);
size_t cell_queues_get_total_allocation(void);
void relay_header_pack(uint8_t *dest, const relay_header_t *src);
void relay_header_unpack(relay_header_t *dest, const uint8_t *src);
MOCK_DECL(int,
relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
uint8_t relay_command, const char *payload,
size_t payload_len, crypt_path_t *cpath_layer,
const char *filename, int lineno));
/* Indicates to relay_send_command_from_edge() that it is a control cell. */
#define CONTROL_CELL_ID 0
#define relay_send_command_from_edge(stream_id, circ, relay_command, payload, \
payload_len, cpath_layer) \
relay_send_command_from_edge_((stream_id), (circ), (relay_command), \
(payload), (payload_len), (cpath_layer), \
__FILE__, __LINE__)
int connection_edge_send_command(edge_connection_t *fromconn,
uint8_t relay_command, const char *payload,
size_t payload_len);
int connection_edge_package_raw_inbuf(edge_connection_t *conn,
int package_partial,
int *max_cells);
void connection_edge_consider_sending_sendme(edge_connection_t *conn);
void circuit_reset_sendme_randomness(circuit_t *circ);
extern uint64_t stats_n_data_cells_packaged;
extern uint64_t stats_n_data_bytes_packaged;
extern uint64_t stats_n_data_cells_received;
extern uint64_t stats_n_data_bytes_received;
extern uint64_t oom_stats_n_bytes_removed_dns;
extern uint64_t oom_stats_n_bytes_removed_cell;
extern uint64_t oom_stats_n_bytes_removed_geoip;
extern uint64_t oom_stats_n_bytes_removed_hsdir;
void dump_cell_pool_usage(int severity);
size_t packed_cell_mem_cost(void);
int have_been_under_memory_pressure(void);
/* For channeltls.c */
void packed_cell_free_(packed_cell_t *cell);
#define packed_cell_free(cell) \
FREE_AND_NULL(packed_cell_t, packed_cell_free_, (cell))
void cell_queue_init(cell_queue_t *queue);
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
void cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
int exitward, const cell_t *cell,
int wide_circ_ids, int use_stats);
int append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream);
void destroy_cell_queue_init(destroy_cell_queue_t *queue);
void destroy_cell_queue_clear(destroy_cell_queue_t *queue);
void destroy_cell_queue_append(destroy_cell_queue_t *queue,
circid_t circid,
uint8_t reason);
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
MOCK_DECL(int, channel_flush_from_first_active_circuit,
(channel_t *chan, int max));
MOCK_DECL(int, circuit_package_relay_cell, (cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
crypt_path_t *layer_hint, streamid_t on_stream,
const char *filename, int lineno));
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
const char *file, int lineno);
#define update_circuit_on_cmux(circ, direction) \
update_circuit_on_cmux_((circ), (direction), SHORT_FILE__, __LINE__)
int append_address_to_payload(uint8_t *payload_out, const tor_addr_t *addr);
const uint8_t *decode_address_from_payload(tor_addr_t *addr_out,
const uint8_t *payload,
int payload_len);
void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids);
uint8_t packed_cell_get_command(const packed_cell_t *cell, int wide_circ_ids);
#ifdef RELAY_PRIVATE
STATIC int
handle_relay_cell_command(cell_t *cell, circuit_t *circ,
edge_connection_t *conn, crypt_path_t *layer_hint,
relay_header_t *rh, int optimistic_data);
STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out);
/** An address-and-ttl tuple as yielded by resolved_cell_parse */
typedef struct address_ttl_t {
tor_addr_t addr;
char *hostname;
int ttl;
} address_ttl_t;
STATIC void address_ttl_free_(address_ttl_t *addr);
#define address_ttl_free(addr) \
FREE_AND_NULL(address_ttl_t, address_ttl_free_, (addr))
STATIC int resolved_cell_parse(const cell_t *cell, const relay_header_t *rh,
smartlist_t *addresses_out, int *errcode_out);
STATIC int connection_edge_process_resolved_cell(edge_connection_t *conn,
const cell_t *cell,
const relay_header_t *rh);
STATIC packed_cell_t *packed_cell_new(void);
STATIC packed_cell_t *cell_queue_pop(cell_queue_t *queue);
STATIC destroy_cell_t *destroy_cell_queue_pop(destroy_cell_queue_t *queue);
STATIC int cell_queues_check_size(void);
STATIC int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
edge_connection_t *conn,
crypt_path_t *layer_hint);
STATIC size_t get_pad_cell_offset(size_t payload_len);
STATIC size_t connection_edge_get_inbuf_bytes_to_package(size_t n_available,
int package_partial,
circuit_t *on_circuit);
#endif /* defined(RELAY_PRIVATE) */
#endif /* !defined(TOR_RELAY_H) */
@@ -0,0 +1,38 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file relay_crypto_st.h
* @brief Relay-cell encryption state structure.
**/
#ifndef RELAY_CRYPTO_ST_H
#define RELAY_CRYPTO_ST_H
#define crypto_cipher_t aes_cnt_cipher_t
struct crypto_cipher_t;
struct crypto_digest_t;
struct relay_crypto_t {
/* crypto environments */
/** Encryption key and counter for cells heading towards the OR at this
* step. */
struct crypto_cipher_t *f_crypto;
/** Encryption key and counter for cells heading back from the OR at this
* step. */
struct crypto_cipher_t *b_crypto;
/** Digest state for cells heading towards the OR at this step. */
struct crypto_digest_t *f_digest; /* for integrity checking */
/** Digest state for cells heading away from the OR at this step. */
struct crypto_digest_t *b_digest;
/** Digest used for the next SENDME cell if any. */
uint8_t sendme_digest[DIGEST_LEN];
};
#undef crypto_cipher_t
#endif /* !defined(RELAY_CRYPTO_ST_H) */
@@ -0,0 +1,219 @@
/* * Copyright (c) 2017-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file scheduler.h
* \brief Header file for scheduler*.c
**/
#ifndef TOR_SCHEDULER_H
#define TOR_SCHEDULER_H
#include "core/or/or.h"
#include "core/or/channel.h"
#include "lib/testsupport/testsupport.h"
/** Scheduler type, we build an ordered list with those values from the
* parsed strings in Schedulers. The reason to do such a thing is so we can
* quickly and without parsing strings select the scheduler at anytime. */
typedef enum {
SCHEDULER_NONE = -1,
SCHEDULER_VANILLA = 1,
SCHEDULER_KIST = 2,
SCHEDULER_KIST_LITE = 3,
} scheduler_types_t;
/**
* A scheduler implementation is a collection of function pointers. If you
* would like to add a new scheduler called foo, create scheduler_foo.c,
* implement at least the mandatory ones, and implement get_foo_scheduler()
* that returns a complete scheduler_t for your foo scheduler. See
* scheduler_kist.c for an example.
*
* These function pointers SHOULD NOT be used anywhere outside of the
* scheduling source files. The rest of Tor should communicate with the
* scheduling system through the functions near the bottom of this file, and
* those functions will call into the current scheduler implementation as
* necessary.
*
* If your scheduler doesn't need to implement something (for example: it
* doesn't create any state for itself, thus it has nothing to free when Tor
* is shutting down), then set that function pointer to NULL.
*/
typedef struct scheduler_t {
/* Scheduler type. This is used for logging when the scheduler is switched
* during runtime. */
scheduler_types_t type;
/* (Optional) To be called when we want to prepare a scheduler for use.
* Perhaps Tor just started and we are the lucky chosen scheduler, or
* perhaps Tor is switching to this scheduler. No matter the case, this is
* where we would prepare any state and initialize parameters. You might
* think of this as the opposite of free_all(). */
void (*init)(void);
/* (Optional) To be called when we want to tell the scheduler to delete all
* of its state (if any). Perhaps Tor is shutting down or perhaps we are
* switching schedulers. */
void (*free_all)(void);
/* (Mandatory) Libevent controls the main event loop in Tor, and this is
* where we register with libevent the next execution of run_sched_ev [which
* ultimately calls run()]. */
void (*schedule)(void);
/* (Mandatory) This is the heart of a scheduler! This is where the
* excitement happens! Here libevent has given us the chance to execute, and
* we should do whatever we need to do in order to move some cells from
* their circuit queues to output buffers in an intelligent manner. We
* should do this quickly. When we are done, we'll try to schedule() ourself
* if more work needs to be done to setup the next scheduling run. */
void (*run)(void);
/*
* External event not related to the scheduler but that can influence it.
*/
/* (Optional) To be called whenever Tor finds out about a new consensus.
* First the scheduling system as a whole will react to the new consensus
* and change the scheduler if needed. After that, the current scheduler
* (which might be new) will call this so it has the chance to react to the
* new consensus too. If there's a consensus parameter that your scheduler
* wants to keep an eye on, this is where you should check for it. */
void (*on_new_consensus)(void);
/* (Optional) To be called when a channel is being freed. Sometimes channels
* go away (for example: the relay on the other end is shutting down). If
* the scheduler keeps any channel-specific state and has memory to free
* when channels go away, implement this and free it here. */
void (*on_channel_free)(const channel_t *);
/* (Optional) To be called whenever Tor is reloading configuration options.
* For example: SIGHUP was issued and Tor is rereading its torrc. A
* scheduler should use this as an opportunity to parse and cache torrc
* options so that it doesn't have to call get_options() all the time. */
void (*on_new_options)(void);
} scheduler_t;
/*****************************************************************************
* Globally visible scheduler variables/values
*
* These are variables/constants that all of Tor should be able to see.
*****************************************************************************/
/* Default interval that KIST runs (in ms). */
#define KIST_SCHED_RUN_INTERVAL_DEFAULT 2
/* Minimum interval that KIST runs. */
#define KIST_SCHED_RUN_INTERVAL_MIN 2
/* Maximum interval that KIST runs (in ms). */
#define KIST_SCHED_RUN_INTERVAL_MAX 100
/*****************************************************************************
* Globally visible scheduler functions
*
* These functions are how the rest of Tor communicates with the scheduling
* system.
*****************************************************************************/
void scheduler_init(void);
void scheduler_free_all(void);
void scheduler_conf_changed(void);
void scheduler_notify_networkstatus_changed(void);
MOCK_DECL(void, scheduler_release_channel, (channel_t *chan));
/*
* Ways for a channel to interact with the scheduling system. A channel only
* really knows (i) whether or not it has cells it wants to send, and
* (ii) whether or not it would like to write.
*/
void scheduler_channel_wants_writes(channel_t *chan);
MOCK_DECL(void, scheduler_channel_doesnt_want_writes, (channel_t *chan));
MOCK_DECL(void, scheduler_channel_has_waiting_cells, (channel_t *chan));
/*****************************************************************************
* Private scheduler functions
*
* These functions are only visible to the scheduling system, the current
* scheduler implementation, and tests.
*****************************************************************************/
#ifdef SCHEDULER_PRIVATE
#include "ext/ht.h"
/*********************************
* Defined in scheduler.c
*********************************/
void scheduler_set_channel_state(channel_t *chan, int new_state);
const char *get_scheduler_state_string(int scheduler_state);
/* Triggers a BUG() and extra information with chan if available. */
#define SCHED_BUG(cond, chan) \
(PREDICT_UNLIKELY(cond) ? \
((BUG(cond)) ? (scheduler_bug_occurred(chan), 1) : 0) : 0)
void scheduler_bug_occurred(const channel_t *chan);
smartlist_t *get_channels_pending(void);
MOCK_DECL(int, scheduler_compare_channels,
(const void *c1_v, const void *c2_v));
void scheduler_ev_active(void);
void scheduler_ev_add(const struct timeval *next_run);
#ifdef TOR_UNIT_TESTS
extern smartlist_t *channels_pending;
extern struct mainloop_event_t *run_sched_ev;
extern const scheduler_t *the_scheduler;
void scheduler_touch_channel(channel_t *chan);
#endif /* defined(TOR_UNIT_TESTS) */
/*********************************
* Defined in scheduler_kist.c
*********************************/
#ifdef SCHEDULER_KIST_PRIVATE
/* Socket table entry which holds information of a channel's socket and kernel
* TCP information. Only used by KIST. */
typedef struct socket_table_ent_t {
HT_ENTRY(socket_table_ent_t) node;
const channel_t *chan;
/* Amount written this scheduling run */
uint64_t written;
/* Amount that can be written this scheduling run */
uint64_t limit;
/* TCP info from the kernel */
uint32_t cwnd;
uint32_t unacked;
uint32_t mss;
uint32_t notsent;
} socket_table_ent_t;
typedef HT_HEAD(outbuf_table_s, outbuf_table_ent_t) outbuf_table_t;
MOCK_DECL(int, channel_should_write_to_kernel,
(outbuf_table_t *table, channel_t *chan));
MOCK_DECL(void, channel_write_to_kernel, (channel_t *chan));
MOCK_DECL(void, update_socket_info_impl, (socket_table_ent_t *ent));
int scheduler_can_use_kist(void);
void scheduler_kist_set_full_mode(void);
void scheduler_kist_set_lite_mode(void);
scheduler_t *get_kist_scheduler(void);
int kist_scheduler_run_interval(void);
#ifdef TOR_UNIT_TESTS
extern int32_t sched_run_interval;
#endif /* TOR_UNIT_TESTS */
#endif /* defined(SCHEDULER_KIST_PRIVATE) */
/*********************************
* Defined in scheduler_vanilla.c
*********************************/
scheduler_t *get_vanilla_scheduler(void);
#endif /* defined(SCHEDULER_PRIVATE) */
#endif /* !defined(TOR_SCHEDULER_H) */
@@ -0,0 +1,83 @@
/* Copyright (c) 2019-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file sendme.h
* \brief Header file for sendme.c.
**/
#ifndef TOR_SENDME_H
#define TOR_SENDME_H
#include "core/or/edge_connection_st.h"
#include "core/or/crypt_path_st.h"
#include "core/or/circuit_st.h"
/* Sending SENDME cell. */
void sendme_connection_edge_consider_sending(edge_connection_t *edge_conn);
void sendme_circuit_consider_sending(circuit_t *circ,
crypt_path_t *layer_hint);
/* Processing SENDME cell. */
int sendme_process_circuit_level(crypt_path_t *layer_hint,
circuit_t *circ, const uint8_t *cell_payload,
uint16_t cell_payload_len);
int sendme_process_circuit_level_impl(crypt_path_t *, circuit_t *);
int sendme_process_stream_level(edge_connection_t *conn, circuit_t *circ,
uint16_t cell_body_len);
/* Update deliver window functions. */
int sendme_stream_data_received(edge_connection_t *conn);
int sendme_circuit_data_received(circuit_t *circ, crypt_path_t *layer_hint);
/* Update package window functions. */
int sendme_note_circuit_data_packaged(circuit_t *circ,
crypt_path_t *layer_hint);
int sendme_note_stream_data_packaged(edge_connection_t *conn, size_t len);
/* Record cell digest on circuit. */
void sendme_record_cell_digest_on_circ(circuit_t *circ, crypt_path_t *cpath);
/* Record cell digest as the SENDME digest. */
void sendme_record_received_cell_digest(circuit_t *circ, crypt_path_t *cpath);
void sendme_record_sending_cell_digest(circuit_t *circ, crypt_path_t *cpath);
/* Private section starts. */
#ifdef SENDME_PRIVATE
/* The maximum supported version. Above that value, the cell can't be
* recognized as a valid SENDME. */
#define SENDME_MAX_SUPPORTED_VERSION 1
/* The cell version constants for when emitting a cell. */
#define SENDME_EMIT_MIN_VERSION_DEFAULT 1
#define SENDME_EMIT_MIN_VERSION_MIN 0
#define SENDME_EMIT_MIN_VERSION_MAX UINT8_MAX
/* The cell version constants for when accepting a cell. */
#define SENDME_ACCEPT_MIN_VERSION_DEFAULT 0
#define SENDME_ACCEPT_MIN_VERSION_MIN 0
#define SENDME_ACCEPT_MIN_VERSION_MAX UINT8_MAX
/*
* Unit tests declaractions.
*/
#ifdef TOR_UNIT_TESTS
STATIC int get_emit_min_version(void);
STATIC int get_accept_min_version(void);
STATIC bool cell_version_can_be_handled(uint8_t cell_version);
STATIC ssize_t build_cell_payload_v1(const uint8_t *cell_digest,
uint8_t *payload);
STATIC bool sendme_is_valid(const circuit_t *circ,
const uint8_t *cell_payload,
size_t cell_payload_len);
STATIC bool circuit_sendme_cell_is_next(int deliver_window,
int sendme_inc);
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(SENDME_PRIVATE) */
#endif /* !defined(TOR_SENDME_H) */
@@ -0,0 +1,24 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file server_port_cfg_st.h
* @brief Configuration structure for server ports.
**/
#ifndef SERVER_PORT_CFG_ST_H
#define SERVER_PORT_CFG_ST_H
struct server_port_cfg_t {
/* Server port types (or, dir) only: */
unsigned int no_advertise : 1;
unsigned int no_listen : 1;
unsigned int all_addrs : 1;
unsigned int bind_ipv4_only : 1;
unsigned int bind_ipv6_only : 1;
};
#endif /* !defined(SERVER_PORT_CFG_ST_H) */
@@ -0,0 +1,89 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file socks_request_st.h
* @brief Client request structure.
**/
#ifndef SOCKS_REQUEST_ST_H
#define SOCKS_REQUEST_ST_H
#include "lib/net/socks5_status.h"
#define MAX_SOCKS_REPLY_LEN 1024
#define SOCKS_NO_AUTH 0x00
#define SOCKS_USER_PASS 0x02
/** Please open a TCP connection to this addr:port. */
#define SOCKS_COMMAND_CONNECT 0x01
/** Please turn this FQDN into an IP address, privately. */
#define SOCKS_COMMAND_RESOLVE 0xF0
/** Please turn this IP address into an FQDN, privately. */
#define SOCKS_COMMAND_RESOLVE_PTR 0xF1
/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define SOCKS_COMMAND_IS_CONNECT(c) (((c)==SOCKS_COMMAND_CONNECT) || 0)
#define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \
(c)==SOCKS_COMMAND_RESOLVE_PTR)
/** State of a SOCKS request from a user to an OP. Also used to encode other
* information for non-socks user request (such as those on TransPort and
* DNSPort) */
struct socks_request_t {
/** Which version of SOCKS did the client use? One of "0, 4, 5" -- where
* 0 means that no socks handshake ever took place, and this is just a
* stub connection (e.g. see connection_ap_make_link()). */
uint8_t socks_version;
/** If using socks5 authentication, which authentication type did we
* negotiate? currently we support 0 (no authentication) and 2
* (username/password). */
uint8_t auth_type;
/** What is this stream's goal? One of the SOCKS_COMMAND_* values */
uint8_t command;
/** Which kind of listener created this stream? */
uint8_t listener_type;
size_t replylen; /**< Length of <b>reply</b>. */
uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if
* we want to specify our own socks reply,
* rather than using the default socks4 or
* socks5 socks reply. We use this for the
* two-stage socks5 handshake.
*/
char address[MAX_SOCKS_ADDR_LEN]; /**< What address did the client ask to
connect to/resolve? */
uint16_t port; /**< What port did the client ask to connect to? */
unsigned int has_finished : 1; /**< Has the SOCKS handshake finished? Used to
* make sure we send back a socks reply for
* every connection. */
unsigned int got_auth : 1; /**< Have we received any authentication data? */
/** If this is set, we will choose "no authentication" instead of
* "username/password" authentication if both are offered. Used as input to
* parse_socks. */
unsigned int socks_prefer_no_auth : 1;
/** If set, we can send back the extended error code in the reply. */
unsigned int socks_use_extended_errors : 1;
/** If non zero, this contains the extended error code that should be used
* if the port was configured to use them. */
socks5_reply_status_t socks_extended_error_code;
/** Number of bytes in username; 0 if username is NULL */
size_t usernamelen;
/** Number of bytes in password; 0 if password is NULL */
uint8_t passwordlen;
/** The negotiated username value if any (for socks5), or the entire
* authentication string (for socks4). This value is NOT nul-terminated;
* see usernamelen for its length. */
char *username;
/** The negotiated password value if any (for socks5). This value is NOT
* nul-terminated; see passwordlen for its length. */
char *password;
uint8_t socks5_atyp; /* SOCKS5 address type */
};
#endif /* !defined(SOCKS_REQUEST_ST_H) */
@@ -0,0 +1,26 @@
/* Copyright (c) 2010-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file status.h
* @brief Header for status.c
**/
#ifndef TOR_STATUS_H
#define TOR_STATUS_H
#include "lib/testsupport/testsupport.h"
void note_connection(bool inbound, const connection_t *conn);
void note_circ_closed_for_unrecognized_cells(time_t n_seconds,
uint32_t n_cells);
int log_heartbeat(time_t now);
#ifdef STATUS_PRIVATE
STATIC int count_circuits(void);
STATIC char *secs_to_uptime(long secs);
STATIC char *bytes_to_usage(uint64_t bytes);
#endif
#endif /* !defined(TOR_STATUS_H) */

Some files were not shown because too many files have changed in this diff Show More