Compare commits

..
Author SHA1 Message Date
jack 429c88aa1e Header spacing: tighten gap between #mesh/#geohash and peer count 2025-09-13 23:03:30 +02:00
jack 6f3b61c3df Header: move notes + bookmark to left of #mesh/#geohash 2025-09-13 23:01:15 +02:00
jack 3f1a9686dd chore: commit remaining local changes 2025-09-13 22:58:06 +02:00
jack 179378031a Notes sheet: show timestamp in brackets; drop #abcd from @name 2025-09-13 22:54:40 +02:00
jack 03b70e2c2f Notes sheet: color #abcd suffix as darker green via opacity (match chat) 2025-09-13 22:51:36 +02:00
jack 08782f0196 Location Notes header: remove extra gap before #geohash (drop leading padding) 2025-09-13 22:50:01 +02:00
jack e855a2e40b Notes icon: use sheet count until counter finishes initial load; don’t zero on sheet close\n\n- Compute hasNotes using max(count, sheetCount) while initialLoadComplete is false.\n- Remove sheetNotesCount reset on sheet disappear to avoid transient grey. 2025-09-13 22:46:43 +02:00
jack 2b567bfb97 Notes counter: unsubscribe without clearing count on resubscribe\n\n- Avoid calling cancel() in subscribe; just unsubscribe old sub to prevent wiping count to 0.\n- Prevents green→grey flicker after closing sheet or location updates. 2025-09-13 22:45:43 +02:00
jack a6d98de90e Notes counter UX: avoid grey flicker when closing sheet\n\n- Preserve last count during resubscribe to prevent brief 0 state.\n- Keep existing subscription when building geohash temporarily unavailable; only cancel if none or permission revoked. 2025-09-13 22:41:21 +02:00
jack ea22ccda71 Location Channels: boxed 'bookmarked' section; keep 'remove location access' outside box\n\n- Wrap bookmarked list in a rounded, subtle grey box within the list.\n- Ensure the 'remove location access' button is not inside the box and clears list row background. 2025-09-13 22:38:40 +02:00
jack 19533742ff Notes icon: use green when notes exist (matches app green) 2025-09-13 22:35:12 +02:00
jack e80f725906 Location Channels sheet: use black sheet background like other sheets\n\n- Add backgroundColor and apply to container and list.\n- Hide list default background with scrollContentBackground(.hidden). 2025-09-13 22:29:58 +02:00
jack c7d8c95f8d Notes: standardize on building-level (8 chars) for publish/read\n\n- Use .building geohash when opening notes, reacting to channel updates, and subscribing the counter.\n- Update comments to reflect building-level scope. 2025-09-13 22:28:50 +02:00
jack 743551c10c Header spacing: move #mesh/#geohash closer to notes/bookmark\n\n- Reduce trailing padding on channel badge and leading padding on notes/bookmark to cluster them together.\n- Keeps larger gap before people count for readability. 2025-09-13 22:27:51 +02:00
jack 7da6f95e87 Fix notes icon color: subscribe/count at block-level geohash\n\n- Use block (precision 7) geohash for notes: when opening sheet, on channel changes, and when subscribing the counter.\n- Aligns with LocationNotesManager which publishes at street-level geohash, allowing the counter to detect notes and turn icon blue. 2025-09-13 22:26:34 +02:00
jack bd753af6cb Location Notes: @name regular green, #abcd darker; nudge #hash\n\n- Render '@' and base name in regular green, suffix '#abcd' in darker green.\n- Add extra left padding before '#geohash' in notes header.\n- Increase leading padding for channel badge to push #mesh/#geohash further right. 2025-09-13 22:24:10 +02:00
jack a3f54c5bf8 Location Notes + Header polish\n\n- Header: add space in '@ #geohash' and use darker green for geohash.\n- Notes list: render '@name#abcd' with darker green for #abcd to match chat.\n- Header: move geochat bookmark icon after #geohash badge with consistent spacing. 2025-09-13 22:18:14 +02:00
jack 79a045af39 Header: nudge #mesh/#geohash badge right with leading padding 2025-09-13 22:13:19 +02:00
jack 607acdbfe4 Header spacing: add breathing room between channel badge, notes button, and people count\n\n- Add trailing padding after #mesh/#geohash badge.\n- Add leading padding before notes button and people counter to improve readability. 2025-09-13 22:10:07 +02:00
jack 5b3f1a1350 Location Notes: prefix usernames with @ and lighten #geohash\n\n- Show @ before usernames in notes list.\n- Split header into '@' and '#geohash' and color the geohash with secondary green for consistency. 2025-09-13 22:09:10 +02:00
jack ee4ce4a38e UI: replace textual 'close' with X icon\n\n- AppInfoView (iOS): use xmark icon in nav bar to match Location Notes style.\n- LocationChannelsSheet: use xmark icon for close on iOS/macOS toolbars; add accessibility label. 2025-09-13 22:02:56 +02:00
2833 changed files with 376406 additions and 191173 deletions
-20
View File
@@ -1,20 +0,0 @@
# Prevent Github Languages stats skewing:
# Binaries and assets
**/*.xcframework/** linguist-vendored
**/*.xcassets/** linguist-vendored
# Generated files
**/*.pbxproj linguist-generated
**/*.storyboard linguist-generated
Package.resolved linguist-generated
# Downloaded CSVs
relays/online_relays_gps.csv linguist-vendored
# Docs
**/*.md linguist-documentation
# Configs
Configs/*.xcconfig linguist-documentation
**/*.plist linguist-documentation
-85
View File
@@ -1,85 +0,0 @@
name: Arti Binary Provenance
# The Arti xcframework is a vendored binary; these checks turn the policy in
# docs/ARTI-BINARY-PROVENANCE.md into an enforced gate:
# 1. The checked-in binary must match the hash manifest in the provenance doc.
# 2. A PR that changes the binary must also change at least one provenance
# input (Rust source, lockfile, build script, or the doc itself).
on:
push:
branches:
- main
paths:
- "localPackages/Arti/**"
- "docs/ARTI-BINARY-PROVENANCE.md"
pull_request:
paths:
- "localPackages/Arti/**"
- "docs/ARTI-BINARY-PROVENANCE.md"
jobs:
verify-hashes:
name: Verify xcframework hashes against provenance doc
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Compare artifact hashes with manifest
run: |
set -euo pipefail
doc="docs/ARTI-BINARY-PROVENANCE.md"
# Extract the manifest: lines of "<sha256> <path>" from the doc.
grep -E '^[0-9a-f]{64} localPackages/Arti/Frameworks/arti\.xcframework/' "$doc" \
| sort -k2 > expected.txt
if [ ! -s expected.txt ]; then
echo "::error::No hash manifest found in $doc"
exit 1
fi
# Hash the same file set the doc documents.
find localPackages/Arti/Frameworks/arti.xcframework -maxdepth 3 -type f -print0 \
| sort -z | xargs -0 sha256sum | sed 's/ \.\// /' | sort -k2 > actual.txt
if ! diff -u expected.txt actual.txt; then
echo "::error::Checked-in arti.xcframework does not match the manifest in $doc. If the binary change is intentional, rebuild per the doc and update the manifest in the same PR."
exit 1
fi
echo "All $(wc -l < actual.txt) artifact hashes match the provenance manifest."
require-provenance-evidence:
name: Binary changes must ship with provenance inputs
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Check changed files
run: |
set -euo pipefail
base="origin/${{ github.base_ref }}"
git fetch --no-tags --depth=1 origin "${{ github.base_ref }}"
changed=$(git diff --name-only "$base"...HEAD)
echo "Changed files:"
echo "$changed"
if ! echo "$changed" | grep -q '^localPackages/Arti/Frameworks/arti\.xcframework/'; then
echo "No binary artifact changes; nothing to verify."
exit 0
fi
if echo "$changed" | grep -Eq '^(localPackages/Arti/(Cargo\.(toml|lock)|build-ios\.sh|arti-bitchat/)|docs/ARTI-BINARY-PROVENANCE\.md)'; then
echo "Binary change is accompanied by provenance inputs."
exit 0
fi
echo "::error::arti.xcframework changed without matching source, lockfile, build-script, or provenance-doc changes. See docs/ARTI-BINARY-PROVENANCE.md (\"Do not accept an xcframework-only update\")."
exit 1
+21 -209
View File
@@ -1,228 +1,40 @@
name: Propose GeoRelay Data Update name: Fetch GeoRelays Data
on: on:
schedule: schedule:
- cron: "0 6 * * 0" - cron: '0 6 * * 0'
workflow_dispatch: workflow_dispatch:
# Default to read-only. The publishing job receives only the scopes required
# to push its branch and publish either a PR or a tracking issue.
permissions: permissions:
contents: read contents: write
concurrency:
group: georelay-data-update
cancel-in-progress: false
env:
SOURCE_REPOSITORY: https://github.com/permissionlesstech/georelays.git
UPDATE_BRANCH: automation/georelay-data
TRACKING_ISSUE_TITLE: GeoRelay update awaiting pull request
jobs: jobs:
propose-relay-data: update-relay-data:
name: Validate and propose relay data
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
issues: write
steps: steps:
- name: Checkout reviewed base - name: Checkout repository
# Pinned actions/checkout v5 so a mutable action tag cannot change the uses: actions/checkout@v4
# code that receives this job's write-capable token.
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
with: with:
ref: main token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
# Do not expose the write token to fetch/validation subprocesses.
persist-credentials: false
- name: Test GeoRelay validator - name: Fetch GeoRelays
run: | run: |
set -euo pipefail wget https://raw.githubusercontent.com/permissionlesstech/georelays/refs/heads/main/nostr_relays.csv
python3 -m unittest discover -s scripts/tests -p "test_*.py" -v mv nostr_relays.csv ./relays/online_relays_gps.csv
- name: Fetch candidate over pinned HTTPS policy - name: Check for changes
id: upstream id: git-check
run: | run: |
set -euo pipefail git diff --exit-code || echo "changes=true" >> $GITHUB_OUTPUT
source_commit=$(git ls-remote --refs "$SOURCE_REPOSITORY" refs/heads/main | awk 'NR == 1 { print $1 }')
if [[ ! "$source_commit" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::Could not resolve an immutable upstream commit"
exit 1
fi
source_url="https://raw.githubusercontent.com/permissionlesstech/georelays/$source_commit/nostr_relays.csv"
effective_url=$(curl --fail --show-error --silent --location --proto "=https" --proto-redir "=https" --tlsv1.2 --max-time 60 --retry 3 --retry-all-errors --output "$RUNNER_TEMP/georelays-candidate.csv" --write-out "%{url_effective}" "$source_url")
if [[ "$effective_url" != "$source_url" ]]; then
echo "::error::Unexpected GeoRelay redirect target: $effective_url"
exit 1
fi
echo "source_commit=$source_commit" >> "$GITHUB_OUTPUT"
echo "source_url=$source_url" >> "$GITHUB_OUTPUT"
- name: Validate candidate against reviewed baseline - name: Commit and push changes
id: validation if: steps.git-check.outputs.changes == 'true'
run: | run: |
set -euo pipefail git config --local user.email "action@github.com"
python3 scripts/validate_georelays.py --input "$RUNNER_TEMP/georelays-candidate.csv" --baseline relays/online_relays_gps.csv --output relays/online_relays_gps.csv --github-output "$GITHUB_OUTPUT" git config --local user.name "GitHub Action"
git add relays/online_relays_gps.csv
- name: Check for a reviewed-file change git commit -m "Automated update of relay data - $(date -u)"
id: changes git push
run: |
set -euo pipefail
if git diff --quiet -- relays/online_relays_gps.csv; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "Upstream GeoRelay data already matches main." >> "$GITHUB_STEP_SUMMARY"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
git diff --stat -- relays/online_relays_gps.csv
fi
- name: Push automation branch and publish review request
if: steps.changes.outputs.changed == 'true'
env: env:
GH_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SOURCE_COMMIT: ${{ steps.upstream.outputs.source_commit }}
SOURCE_URL: ${{ steps.upstream.outputs.source_url }}
DATA_ROWS: ${{ steps.validation.outputs.data_rows }}
UNIQUE_RELAYS: ${{ steps.validation.outputs.unique_relays }}
DATA_SHA256: ${{ steps.validation.outputs.sha256 }}
run: |
set -euo pipefail
# Scope credential exposure to this final publishing step.
gh auth setup-git
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git switch -C "$UPDATE_BRANCH"
git add -- relays/online_relays_gps.csv
git diff --cached --quiet && {
echo "::error::Expected a staged GeoRelay data change"
exit 1
}
git commit -m "Update reviewed georelay directory" -m "Upstream-commit: $SOURCE_COMMIT"
remote_ref="refs/remotes/origin/$UPDATE_BRANCH"
if git fetch --no-tags origin "+refs/heads/$UPDATE_BRANCH:$remote_ref" 2>/dev/null; then
remote_sha=$(git rev-parse "$remote_ref")
git push --force-with-lease="refs/heads/$UPDATE_BRANCH:$remote_sha" origin "HEAD:refs/heads/$UPDATE_BRANCH"
else
git push origin "HEAD:refs/heads/$UPDATE_BRANCH"
fi
body_file="$RUNNER_TEMP/georelay-pr-body.md"
{
echo "## Automated GeoRelay data proposal"
echo
echo "- Source: $SOURCE_URL"
echo "- Upstream commit: $SOURCE_COMMIT"
echo "- Data rows: $DATA_ROWS"
echo "- Unique normalized relays: $UNIQUE_RELAYS"
echo "- SHA-256: $DATA_SHA256"
echo
echo "The candidate passed strict UTF-8, schema, size, row-count, secure-host, coordinate, duplicate-conflict, and baseline-delta validation."
echo
echo "This PR is intentionally not auto-merged. Review the relay additions/removals before merging."
} > "$body_file"
existing_pr=$(gh pr list --repo "$GITHUB_REPOSITORY" --state open --base main --head "$UPDATE_BRANCH" --json number --jq '.[0].number // empty')
pr_error="$RUNNER_TEMP/georelay-pr-error.txt"
pr_url=""
if [[ -n "$existing_pr" ]]; then
if gh pr edit "$existing_pr" --repo "$GITHUB_REPOSITORY" --title "Update reviewed GeoRelay directory" --body-file "$body_file" 2> "$pr_error"; then
pr_url=$(gh pr view "$existing_pr" --repo "$GITHUB_REPOSITORY" --json url --jq .url)
fi
else
if created_pr_url=$(gh pr create --repo "$GITHUB_REPOSITORY" --base main --head "$UPDATE_BRANCH" --title "Update reviewed GeoRelay directory" --body-file "$body_file" 2> "$pr_error"); then
pr_url="$created_pr_url"
fi
fi
tracking_issue_numbers=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --search "\"$TRACKING_ISSUE_TITLE\" in:title" --limit 100 --json number,title --jq ".[] | select(.title == \"$TRACKING_ISSUE_TITLE\") | .number")
tracking_issues=()
if [[ -n "$tracking_issue_numbers" ]]; then
mapfile -t tracking_issues <<< "$tracking_issue_numbers"
fi
if [[ -n "$pr_url" ]]; then
for issue_number in "${tracking_issues[@]}"; do
gh issue close "$issue_number" --repo "$GITHUB_REPOSITORY" --comment "A pull request is now available at $pr_url; closing this fallback tracking issue."
done
echo "Published GeoRelay review PR: $pr_url" >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
echo "::warning::GITHUB_TOKEN could not create or update the GeoRelay pull request; publishing the issues-write fallback."
if [[ -s "$pr_error" ]]; then
cat "$pr_error" >&2
fi
compare_url="https://github.com/${GITHUB_REPOSITORY}/compare/main...${UPDATE_BRANCH}?expand=1"
issue_body_file="$RUNNER_TEMP/georelay-tracking-issue-body.md"
{
echo "## Validated GeoRelay update awaiting review"
echo
echo "The automation branch was updated, but this workflow token could not create or update the pull request. Use the compare link below to create it manually."
echo
echo "- Compare and create PR: $compare_url"
echo "- Automation branch: $UPDATE_BRANCH"
echo "- Source: $SOURCE_URL"
echo "- Upstream commit: $SOURCE_COMMIT"
echo "- Data rows: $DATA_ROWS"
echo "- Unique normalized relays: $UNIQUE_RELAYS"
echo "- SHA-256: $DATA_SHA256"
echo
echo "The snapshot passed the repository's strict validator before the branch was pushed."
} > "$issue_body_file"
if (( ${#tracking_issues[@]} > 0 )); then
primary_issue="${tracking_issues[0]}"
gh issue edit "$primary_issue" --repo "$GITHUB_REPOSITORY" --title "$TRACKING_ISSUE_TITLE" --body-file "$issue_body_file"
issue_url=$(gh issue view "$primary_issue" --repo "$GITHUB_REPOSITORY" --json url --jq .url)
for duplicate_issue in "${tracking_issues[@]:1}"; do
gh issue close "$duplicate_issue" --repo "$GITHUB_REPOSITORY" --comment "Closing duplicate GeoRelay automation tracking issue; #$primary_issue is canonical."
done
else
issue_url=$(gh issue create --repo "$GITHUB_REPOSITORY" --title "$TRACKING_ISSUE_TITLE" --body-file "$issue_body_file")
fi
# Do not claim success until the fallback issue was confirmed.
[[ -n "$issue_url" ]]
echo "Published GeoRelay tracking issue fallback: $issue_url" >> "$GITHUB_STEP_SUMMARY"
- name: Clean obsolete automation review state
if: steps.changes.outputs.changed == 'false'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh auth setup-git
existing_pr=$(gh pr list --repo "$GITHUB_REPOSITORY" --state open --base main --head "$UPDATE_BRANCH" --json number --jq '.[0].number // empty')
if [[ -n "$existing_pr" ]]; then
gh pr close "$existing_pr" --repo "$GITHUB_REPOSITORY" --comment "Upstream now matches the reviewed file on main; closing this obsolete automation proposal."
echo "Closed obsolete PR #$existing_pr." >> "$GITHUB_STEP_SUMMARY"
fi
tracking_issue_numbers=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --search "\"$TRACKING_ISSUE_TITLE\" in:title" --limit 100 --json number,title --jq ".[] | select(.title == \"$TRACKING_ISSUE_TITLE\") | .number")
if [[ -n "$tracking_issue_numbers" ]]; then
while IFS= read -r issue_number; do
gh issue close "$issue_number" --repo "$GITHUB_REPOSITORY" --comment "Upstream now matches the reviewed file on main; closing this obsolete automation tracker."
echo "Closed obsolete tracking issue #$issue_number." >> "$GITHUB_STEP_SUMMARY"
done <<< "$tracking_issue_numbers"
fi
if git ls-remote --exit-code --heads origin "refs/heads/$UPDATE_BRANCH" > /dev/null; then
git push origin --delete "$UPDATE_BRANCH"
echo "Deleted obsolete automation branch $UPDATE_BRANCH." >> "$GITHUB_STEP_SUMMARY"
else
ls_remote_status=$?
if (( ls_remote_status != 2 )); then
echo "::error::Could not inspect the obsolete automation branch"
exit "$ls_remote_status"
fi
fi
-30
View File
@@ -1,30 +0,0 @@
name: Dead Code
on:
push:
branches:
- main
pull_request:
jobs:
periphery:
name: Periphery scan
runs-on: macos-latest
timeout-minutes: 30
# Advisory, like SwiftLint (#1361): findings annotate the PR but don't
# block merges. Drop continue-on-error once the baseline proves stable.
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Install Periphery
# homebrew-core formula; the peripheryapp tap lags years behind.
run: brew install periphery
- name: Scan for dead code
# Config comes from .periphery.yml; known findings (mostly iOS-only
# code invisible to a macOS scan) are suppressed by the committed
# baseline. --strict fails the step when NEW dead code appears.
run: periphery scan --strict --disable-update-check
+8 -175
View File
@@ -5,190 +5,23 @@ on:
branches: branches:
- main - main
pull_request: pull_request:
branches:
- main
jobs: jobs:
test: test:
name: Run Swift Tests (${{ matrix.name }}) name: Run Swift Tests
runs-on: macos-latest runs-on: macos-latest
# A hung test must fail fast, not hold a runner for GitHub's 360-minute
# default (observed: intermittent app-suite hangs starving the queue).
# The long steps carry tighter individual bounds (5-minute test watchdog,
# 6-minute benchmark step, 10-minute floor gate that may re-run the
# benchmarks up to twice on a noisy runner); this is the backstop.
timeout-minutes: 25
strategy:
fail-fast: false # Don't cancel other matrix jobs when one fails
matrix:
include:
- name: app
path: .
- name: BitLogger
path: localPackages/BitLogger
- name: BitFoundation
path: localPackages/BitFoundation
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v5 uses: actions/checkout@v5
# Use the Xcode-bundled Swift toolchain: it always matches the SDK on - name: Set up Swift
# the runner image. A standalone swift.org toolchain (setup-swift) broke uses: swift-actions/setup-swift@v2
# whenever the image's Xcode moved ahead of it ("this SDK is not
# supported by the compiler").
- name: Note toolchain version (cache key)
id: swift-version
run: echo "version=$(swift --version 2>/dev/null | head -1 | shasum | cut -c1-12)" >> "$GITHUB_OUTPUT"
- name: Cache build artifacts - name: Build the package
uses: actions/cache@v4 run: swift build
with:
path: ${{ matrix.path }}/.build
key: ${{ runner.os }}-${{ steps.swift-version.outputs.version }}-${{ matrix.name }}-${{ hashFiles(format('{0}/**/*.swift', matrix.path), format('{0}/**/Package.resolved', matrix.path)) }}
restore-keys: |
${{ runner.os }}-${{ steps.swift-version.outputs.version }}-${{ matrix.name }}-${{ hashFiles(format('{0}/**/Package.resolved', matrix.path)) }}
${{ runner.os }}-${{ steps.swift-version.outputs.version }}-${{ matrix.name }}-
- name: Build tests
# Built separately so the hang watchdog below times only test
# execution: a cold-cache coverage build on a slow runner can
# legitimately take several minutes, and is already bounded by the
# 15-minute job timeout.
run: swift build --build-tests --enable-code-coverage --package-path ${{ matrix.path }}
- name: Run Tests - name: Run Tests
# Perf benchmarks are excluded here and run in their own serial step run: swift test --parallel --disable-swift-testing # so it only runs xctests: https://github.com/swiftlang/swift-package-manager/issues/8529#issuecomment-2815711345
# below: measuring while parallel test processes contend for cores
# produces noisy numbers, and the XCTest measure machinery has hung
# intermittently under parallel workers on loaded runners. Excluded
# via --skip (not just the env guard): every app run since the
# baselines landed timed out at the 15-minute job limit with the
# baseline tests dispatched into the parallel phase.
#
# The watchdog samples any still-running test processes after 5
# minutes (the suite passes in seconds when healthy; the build is
# done by this step) and kills the run, so a hang fails fast with
# stacks in the log instead of a silent timeout.
env:
BITCHAT_SKIP_PERF_BASELINES: "1"
run: |
swift test --skip-build --parallel --quiet --enable-code-coverage \
--skip PerformanceBaselineTests \
--package-path ${{ matrix.path }} &
test_pid=$!
(
sleep 300
if kill -0 "$test_pid" 2>/dev/null; then
echo "::group::Tests still running after 5 minutes — sampling before kill"
for pid in $(pgrep -if 'swiftpm-testing|xctest|PackageTests' || true); do
echo "--- sample of pid $pid ---"
sample "$pid" 5 2>/dev/null || true
done
echo "::endgroup::"
pkill -KILL -P "$test_pid" 2>/dev/null || true
kill -KILL "$test_pid" 2>/dev/null || true
fi
) &
watchdog_pid=$!
wait "$test_pid" && status=0 || status=$?
kill "$watchdog_pid" 2>/dev/null || true
exit "$status"
# Benchmarks run serially on an otherwise idle runner for stable
# numbers; BITCHAT_PERF_LOG captures the PERF[...] lines for the gate.
- name: Run performance benchmarks (serial)
if: matrix.name == 'app'
timeout-minutes: 6
env:
BITCHAT_PERF_LOG: ${{ github.workspace }}/perf-output.log
run: swift test --quiet --filter PerformanceBaselineTests
# Order-of-magnitude performance regression gate. Floors are deliberately
# generous (see bitchatTests/Performance/perf-floors.json) so this
# catches algorithmic regressions, never runner variance. If a metric
# still lands below floor (a saturated runner can dip one), the script
# re-runs the benchmarks — appending to the same log and keeping each
# benchmark's best value per metric — so noise clears on retry while a
# real regression fails every attempt. Floors are never lowered by this.
- name: Performance floor gate
if: matrix.name == 'app'
timeout-minutes: 10
run: ./scripts/check-perf-floors.sh perf-output.log
# Informational only: surfaces per-file and total line coverage in the
# job log so coverage trends are visible on every PR. No thresholds —
# this must never be the reason a build goes red.
- name: Coverage summary
run: |
BIN_PATH=$(swift build --show-bin-path --package-path ${{ matrix.path }})
PROF="$BIN_PATH/codecov/default.profdata"
XCTEST=$(find "$BIN_PATH" -maxdepth 1 -name '*.xctest' | head -1)
BINARY="$XCTEST/Contents/MacOS/$(basename "$XCTEST" .xctest)"
if [ -f "$PROF" ] && [ -f "$BINARY" ]; then
xcrun llvm-cov report "$BINARY" -instr-profile "$PROF" \
-ignore-filename-regex='(Tests|\.build|checkouts|Mocks|_PreviewHelpers)' || true
else
echo "No coverage data found; skipping summary."
fi
# SPM tests do not link the shipping app targets. This job covers the
# iOS-conditional paths and both universal Release link configurations.
ios-build:
name: Build Release apps (universal)
runs-on: macos-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Build iOS (simulator, no signing)
# Build both simulator architectures so CI validates every vendored
# Arti simulator slice and the configuration that ships.
run: |
set -o pipefail
xcodebuild -project bitchat.xcodeproj \
-scheme "bitchat (iOS)" \
-configuration Release \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
ARCHS='arm64 x86_64' \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
build
- name: Build macOS (universal, no signing)
run: |
set -o pipefail
xcodebuild -project bitchat.xcodeproj \
-scheme "bitchat (macOS)" \
-configuration Release \
-destination 'generic/platform=macOS' \
ARCHS='arm64 x86_64' \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
build
# Advisory only: SwiftLint reports style violations without ever failing the
# build. Runs in a pinned container (no Xcode plugin, no pbxproj changes) so
# it can never break the documented xcodebuild path or block a merge.
lint:
name: SwiftLint (advisory)
runs-on: ubuntu-latest
timeout-minutes: 15
# This job runs a third-party container image, so give it the least
# privilege we can: a read-only token, and no credentials left in the
# checkout for the container to find.
permissions:
contents: read
container:
# Tag for readability, digest for immutability (tags can be repointed).
# Bump both together, deliberately — never a floating tag.
image: ghcr.io/realm/swiftlint:0.65.0@sha256:a482729f4b58741875af1566f23397f3f6db300372756fc31606d0a4527fab9e
continue-on-error: true
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Run SwiftLint
run: swiftlint lint --reporter github-actions-logging
+4 -9
View File
@@ -8,7 +8,9 @@ plans/
## AI ## AI
CLAUDE.md CLAUDE.md
AGENTS.md AGENTS.md
.claude/
## User settings
xcuserdata/
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint *.xcscmblueprint
@@ -55,8 +57,7 @@ iOSInjectionProject/
## Xcode project ## Xcode project
*.xcodeproj/project.xcworkspace/ *.xcodeproj/project.xcworkspace/
## Xcode User settings *.xcodeproj/xcshareddata/
xcuserdata/
## Python ## Python
__pycache__/ __pycache__/
@@ -67,9 +68,6 @@ __pycache__/
*.tmp *.tmp
*.temp *.temp
## Cache
.cache/
# Local build results # Local build results
.Result*/ .Result*/
.Result*.xcresult/ .Result*.xcresult/
@@ -77,6 +75,3 @@ TestResult.xcresult/
*.xcresult/ *.xcresult/
build.log build.log
*.log *.log
# Local configs
Local.xcconfig
-1
View File
@@ -1 +0,0 @@
{"v1":{"usrs":["param-buf-arti_bootstrap_summary(_:_:)-s:3Tor22arti_bootstrap_summary33_954FD7701B4E47ABB5F166D1CF862DC9LLys5Int32VSpys4Int8VG_AEtF","param-dataDir-arti_start(_:_:)-s:3Tor10arti_start33_954FD7701B4E47ABB5F166D1CF862DC9LLys5Int32VSPys4Int8VG_s6UInt16VtF","param-len-arti_bootstrap_summary(_:_:)-s:3Tor22arti_bootstrap_summary33_954FD7701B4E47ABB5F166D1CF862DC9LLys5Int32VSpys4Int8VG_AEtF","param-socksPort-arti_start(_:_:)-s:3Tor10arti_start33_954FD7701B4E47ABB5F166D1CF862DC9LLys5Int32VSPys4Int8VG_s6UInt16VtF","s:13BitFoundation16PeerCapabilitiesV8wifiBulkACvpZ","s:13BitFoundation18KeychainReadResultO18isRecoverableErrorSbvp","s:13BitFoundation23KeychainManagerProtocolP11secureClearyySSzF","s:18bitchatTests_macOS12MockKeychainC11secureClearyySSzF","s:18bitchatTests_macOS20TrackingMockKeychainC11resetCountsyyF","s:18bitchatTests_macOS20TrackingMockKeychainC11secureClearyySSzF","s:18bitchatTests_macOS20TrackingMockKeychainC25totalSecureClearCallCountSivp","s:18bitchatTests_macOS20TrackingMockKeychainC26secureClearStringCallCountSivp","s:18bitchatTests_macOS20TrackingMockKeychainC27_secureClearStringCallCount06_AB6D1M24FD239F2969C82F4108818260LLSivp","s:18bitchatTests_macOS24FailingCacheSaveKeychain33_22380C7A11A569A0B83FA83F34C498A7LLC11secureClearyySSzF","s:18bitchatTests_macOS24MockGeohashPresenceTimer33_483587EFB96650EE130EFB09BBA2A1AALLC7handleryycvp","s:3Tor0A7ManagerC21goDormantOnBackgroundyyF","s:7bitchat10AppRuntimeC24handleScreenshotCaptured33_C8B369AD8BC1D9963A50CEDA77A4332ALLyyF","s:7bitchat10AppRuntimeC33handleDidBecomeActiveNotificationyyF","s:7bitchat10BLEServiceC18logBluetoothStatus33_69191C53E68500C17D98DBCF2BDA7100LLyySSF","s:7bitchat10BLEServiceC20centralRestorationID33_69191C53E68500C17D98DBCF2BDA7100LLSSvpZ","s:7bitchat10BLEServiceC22captureBluetoothStatus33_69191C53E68500C17D98DBCF2BDA7100LL7contextySS_tF","s:7bitchat10BLEServiceC23peripheralRestorationID33_69191C53E68500C17D98DBCF2BDA7100LLSSvpZ","s:7bitchat10BLEServiceC29scheduleBluetoothStatusSample33_69191C53E68500C17D98DBCF2BDA7100LL5after7contextySd_SStF","s:7bitchat10QRScanViewV8isActiveSbvp","s:7bitchat15BLEPeerRegistryV5countSivp","s:7bitchat15KeychainManagerC11secureClearyySSzF","s:7bitchat15PaymentChipViewV7openURL33_10AC50641B1EBCD52E5092A2E521D236LL7SwiftUI13OpenURLActionVvp","s:7bitchat15TransportConfigO29uiBatchDispatchStaggerSecondsSdvpZ","s:7bitchat15TransportConfigO35uiShareExtensionDismissDelaySecondsSdvpZ","s:7bitchat15TransportConfigO38bleBackgroundPendingConnectSlotReserveSivpZ","s:7bitchat17GossipSyncManagerC10persistNowyyF","s:7bitchat17NostrRelayManagerC15InboundEventKey33_E4160FE8A9A2C9D6308EAAD5A8B5CB07LLV7eventIDSSvp","s:7bitchat25LocationNotesDependenciesV3now10Foundation4DateVycvp","s:7bitchat25NWPathReachabilityMonitorC7monitor33_84633C9DBCAF57538179C1E04DB8E015LL7Network0bD0CSgvp"]}}
-21
View File
@@ -1,21 +0,0 @@
# Periphery dead-code scan configuration (https://github.com/peripheryapp/periphery)
#
# CI runs the macOS scheme only (an iOS scan needs a device destination and
# doubles the build time). macOS-only scans falsely flag iOS-only code —
# state restoration, screenshot handlers, background BLE sampling — so those
# findings live in .periphery.baseline.json rather than being "fixed".
# When auditing by hand, scan BOTH schemes and intersect:
# periphery scan --schemes "bitchat (iOS)" -- -destination 'generic/platform=iOS' ARCHS=arm64
project: bitchat.xcodeproj
schemes:
- bitchat (macOS)
retain_swift_ui_previews: true
# Codable properties are (de)serialized via synthesized conformances the
# indexer doesn't always attribute reads to: PrekeyBundleStore.StoredBundle
# .noiseKey flaked CI as "assign-only" even while read in loadFromDisk —
# and slipped past its baselined USR. Retaining Codable properties outright
# is deterministic; a truly-dead Codable field is a persisted-format change
# anyway, never a safe mechanical delete.
retain_codable_properties: true
relative_results: true
baseline: .periphery.baseline.json
-34
View File
@@ -1,34 +0,0 @@
# Build artifacts and generated sources; keeps local `swiftlint` runs clean
# (CI checkouts are fresh, so this only matters in a working tree).
excluded:
- .build
- .claude
- .swiftpm
- .DerivedData
- DerivedData
- build
- localPackages/*/.build
disabled_rules:
- line_length
- type_name
- identifier_name
- statement_position
- implicit_optional_initialization
- force_try
- vertical_whitespace
- for_where
- control_statement
- void_function_in_ternary
- redundant_discardable_let # SwiftUI breaks without it
# To be enabled as we fix the issues
- trailing_whitespace
- cyclomatic_complexity
- function_body_length
- function_parameter_count
- type_body_length
- file_length
- large_tuple
- force_cast
- multiple_closures_with_trailing_closure
- nesting
-4
View File
@@ -1,4 +0,0 @@
#include "Release.xcconfig"
// Optional include of local configs
#include? "Local.xcconfig"
-5
View File
@@ -1,5 +0,0 @@
// Your Apple Developer Team ID - https://stackoverflow.com/a/18727947
DEVELOPMENT_TEAM = ABC123
// Unique bundle id to be able to register and run locally
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat.$(DEVELOPMENT_TEAM)
-12
View File
@@ -1,12 +0,0 @@
MARKETING_VERSION = 1.7.1
CURRENT_PROJECT_VERSION = 1
IPHONEOS_DEPLOYMENT_TARGET = 16.0
MACOSX_DEPLOYMENT_TARGET = 13.0
SWIFT_VERSION = 5.0
DEVELOPMENT_TEAM = L3N5LHJD5Y
CODE_SIGN_STYLE = Automatic
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat
APP_GROUP_ID = group.chat.bitchat
+86
View File
@@ -0,0 +1,86 @@
**BitChat Tor Build Notes**
- Date: See repo history for the commit you pulled
- Output: `tor-nolzma.xcframework` (static, C-only)
- Platforms: iOS device (arm64), iOS simulator (arm64), macOS (arm64)
- Goal: Minimize binary size while retaining client functionality
**Overview**
- We built a minimal Tor static xcframework with LZMA disabled to reduce size and complexity.
- The artifact contains only the C libraries (Tor + libevent + OpenSSL) and their headers. ObjectiveC wrappers (`TORThread`, `TORController`, etc.) are not compiled into this minimal artifact to keep size down.
- This xcframework is suitable for iOS and macOS targets that link the ObjectiveC wrappers as source (or use CocoaPods to bring them in).
**Component Versions**
- Tor: 0.4.8.17
- libevent: 2.1.12
- OpenSSL: 3.5.1
- liblzma: not linked (intentionally disabled)
**Build Environment**
- Xcode with iOS and macOS SDKs
- Homebrew tools: `autoconf`, `automake`, `libtool`, `gettext`
- Install prerequisites from repo root: `brew bundle`
**Command Used**
- Minimal build (nolzma), with persistent logs: `./build-xcframework.sh -md`
- `-m` = minimal mode
- `-d` = keep build dir and logs under `build/`
**What Minimal Mode Does**
- Targets: `iphoneos/arm64`, `iphonesimulator/arm64`, `macosx/arm64`.
- Disables LZMA in Tor (`--enable-lzma=no`) and removes zstd.
- Trims OpenSSL features: `no-zlib no-comp no-ssl3 no-tls1 no-tls1_1 no-dtls no-srp no-psk no-weak-ssl-ciphers no-engine no-ocsp`.
- Compiles with size-first flags: `-Os -ffunction-sections -fdata-sections`; bitcode is not embedded.
- Statically links Tor, libevent, and OpenSSL into a single library per slice inside the framework.
- Copies public headers from Tor/libevent/OpenSSL into the framework `Headers` directory.
**Resulting Slices (approx sizes)**
- Folder size: ~73 MB (`tor-nolzma.xcframework`)
- Binaries (non-fat, measured on this build):
- iOS arm64 (device): ~16.49 MB
- iOS arm64 (simulator): ~15.32 MB
- macOS arm64: ~15.60 MB
Note: Sizes vary slightly by Xcode/SDK versions and environment.
**Integrating in BitChat**
- Add `tor-nolzma.xcframework` to your app target(s). Xcode will select the correct slice for device/simulator/macOS.
- Link `libz.tbd` (Tor depends on zlib).
- Keep app link-time stripping enabled for best results:
- Other Linker Flags: add `-dead_strip`
- Avoid `-ObjC` if possible (prevents dead stripping)
- Consider enabling ThinLTO/LTO in the app for further size gains
- ObjectiveC API (wrappers):
- Not included in this minimal xcframework. Use one of:
- CocoaPods: `Tor/CTor-NoLZMA` subspec (brings `TORThread`, `TORController` sources + links the xcframework), or
- Vendor the ObjC sources from `Tor/Classes/CTor` and `Tor/Classes/Core` directly into your project.
**Rebuilding**
- Ensure prerequisites: `brew bundle`
- Minimal nolzma, iOS+sim+macOS: `./build-xcframework.sh -m`
- Logs (if `-d`): `build/*.log` and per-component logs like `build/libtor-nolzma-<sdk>-<arch>.log`
**LZMA Tradeoff (for reference)**
- We measured that enabling LZMA adds roughly ~0.25 MB per slice to the binary on this setup. For a 3slice xcframework, expect ~0.70.8 MB more overall.
- If you want the LZMA variant with the same minimal trimming: `./build-xcframework.sh -Md` (outputs `tor.xcframework`).
**Key Flags (for auditing)**
- OpenSSL `./Configure` adds: `no-shared` and, in minimal modes, `no-zlib no-comp no-ssl3 no-tls1 no-tls1_1 no-dtls no-srp no-psk no-weak-ssl-ciphers no-engine no-ocsp`
- libevent `./configure`: `--disable-openssl --disable-samples --disable-regress --enable-static --disable-shared`
- Tor `./configure` (highlights):
- `--enable-pic --disable-module-relay --disable-module-dirauth --disable-unittests`
- `--enable-static-openssl --enable-static-libevent`
- `--disable-asciidoc --disable-manpage --disable-html-manual --disable-zstd`
- `--enable-lzma=no` (in this build)
- Compiler flags: `-Os -ffunction-sections -fdata-sections`; no bitcode
- Minimum OS: iOS 12.0, macOS 10.13
**Verification Tips**
- Check slices: `lipo -info tor-nolzma.xcframework/*/tor-nolzma.framework/tor-nolzma`
- Ensure headers present: `ls tor-nolzma.xcframework/*/tor-nolzma.framework/Headers`
- Link test: build a small app and add `-dead_strip`; confirm successful run and circuit establishment via control port.
**Notes**
- This minimal build avoids bundling large GeoIP resources. If you need GeoIP, embed the GeoIP bundle (or use the `Tor/GeoIP-NoLZMA` subspec) and set `TORConfiguration.geoipFile`/`geoip6File`.
- Static linking maximizes the apps ability to deadstrip unused code across the boundary.
@@ -0,0 +1,57 @@
<?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>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>
<dict>
<key>BinaryPath</key>
<string>tor-nolzma.framework/tor-nolzma</string>
<key>LibraryIdentifier</key>
<string>ios-arm64-simulator</string>
<key>LibraryPath</key>
<string>tor-nolzma.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<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>
</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) */

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